這是一個使用 React 背景關系的簡單示例:
type MyState = { counter: number };
const MyContext = createContext<[MyState, () => void]|undefined>(undefined);
class MyComponent extends Component<any, MyState> {
constructor(props: any) {
super(props);
this.state = { counter: 42 };
}
render() {
return (
<MyContext.Provider value={[this.state, () => this.setState({ counter: this.state.counter 1 })]}>
{this.props.children}
</MyContext.Provider>
)
}
}
function App() {
return (
<MyComponent>
<MyContext.Consumer>
{
pair => {
const [state, increment] = pair || [];
return (<button onClick={increment}>Click to increment: {state?.counter}</button>);
}
}
</MyContext.Consumer>
</MyComponent>
);
}
這有效,單擊按鈕會按預期遞增計數器。但是當我嘗試將增量器拉到父組件上的方法中時:
type MyState = { counter: number };
const MyContext = createContext<MyComponent|undefined>(undefined);
class MyComponent extends Component<any, MyState> {
constructor(props: any) {
super(props);
this.state = { counter: 42 };
}
render() {
return (
<MyContext.Provider value={this}>
{this.props.children}
</MyContext.Provider>
)
}
increment() {
this.setState({ counter: this.state.counter 1 });
}
}
function App() {
return (
<MyComponent>
<MyContext.Consumer>
{
me => (<button onClick={() => me?.increment()}>Click to increment: {me?.state.counter}</button>)
}
</MyContext.Consumer>
</MyComponent>
);
}
現在該按鈕在單擊時不再重新繪制。
計數器正在遞增,但狀態更改不會傳播給消費者。為什么是這樣?
我想可以使用減速器而不是物件:
type MyState = { counter: number };
type MyAction = { type: "increment" };
const MyContext = createContext<[MyState, React.Dispatch<MyAction>]|undefined>(undefined);
function myReducer(state: MyState, action: MyAction) {
switch (action.type) {
case "increment":
return { counter: state.counter 1 };
default:
throw new Error();
}
}
function MyComponent({ children }: { children: ReactNode }) {
const [state, dispatch] = useReducer(myReducer, { counter: 42 });
return (
<MyContext.Provider value={[state, dispatch]}>
{children}
</MyContext.Provider>
)
}
function App() {
return (
<MyComponent>
<MyContext.Consumer>
{
pair => {
const [state, dispatch] = pair || [];
return (<button onClick={() => dispatch && dispatch({ type: "increment" })}>Click to increment: {state?.counter}</button>);
}
}
</MyContext.Consumer>
</MyComponent>
);
}
但這意味著將已經很好地封裝在一個類中的現有代碼切割成一個帶有大 switch 陳述句的 reducer 函式。有沒有辦法避免這種情況?
uj5u.com熱心網友回復:
我認為你不應該把this背景關系的價值放在你的提供者身上。
當你傳遞時,你() => this.setState({ counter: this.state.counter 1 })]}傳遞的是一個匿名函式 ( () => {}),它運行你的this.setState(). 因為它是一個箭頭函式,所以它保證this.setState并且this.state正在裁判正確的this.
如果您想使用該increment方法,可以繼續使用相同的邏輯:
<MyContext.Provider value={[this.state, () => this.increment()]}>
當然,如果你愿意,你不需要使用陣列,你可以使用一個物件:
<MyContext.Provider value={{ state: this.state, increment: () => this.increment() }}>
這在 React 中很常見,最好只在背景關系中存盤您需要傳遞給消費者的值,這樣您可以更好地了解代碼的哪一部分正在改變什么,并且只能訪問它需要的內容。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/477929.html
