更新时间:2023-12-02 20:42:40
原来我必须将 Context 拆分为两个,一个没有依赖关系,只运行函数,另一个显示任何值) 实时通过添加依赖项.与消费者组件相同,将其作为新组件取出并放入useContext
,这样父组件就不会被重新渲染.
I have three buttons. When I click one button, it fires Context's memo function to add an item into Context's items. I see that clicking one button re-renders all the three buttons, which is not expected. I need to re-render only the clicked button. Please advice.
CounterContext.js
import { createContext } from "react";
export const CounterContext = createContext(null);
App.js
import React from "react";
import { Text, StyleSheet } from "react-native";
import MyButton from "./MyButton";
import { CounterContext } from "./CounterContext";
function counterReducer(prevState, action) {
switch (action.type) {
case "ADD_ITEM":
let items = [...prevState.items, action.item];
return {
items: items,
count: items.length
};
default:
console.log("No action type");
break;
}
}
const buttons = ["1", "2", "3"];
export default function App() {
const [counterState, counterDispatch] = React.useReducer(counterReducer, {
items: [],
count: 0
});
const counterContext = React.useMemo(
() => ({
addItem: item => {
counterDispatch({
type: "ADD_ITEM",
item: item
});
},
items: counterState.items,
itemsCount: counterState.items.length
}),
[counterState.items]
);
return (
<CounterContext.Provider value={counterContext}>
{buttons.map((button, index) => {
return <MyButton key={index} id={button} />;
})}
<Text style={styles.counter}>{counterContext.itemsCount}</Text>
<Text style={styles.items}>{JSON.stringify(counterContext.items)}</Text>
</CounterContext.Provider>
);
}
const styles = StyleSheet.create({
counter: {
margin: 10,
fontSize: 30
},
items: {
margin: 10,
fontSize: 18
}
});
MyButton.js
import React from "react";
import { TouchableOpacity, Text, StyleSheet } from "react-native";
import { CounterContext } from "./CounterContext";
export default function MyButton(props) {
const { addItem } = React.useContext(CounterContext);
let time = new Date().toLocaleTimeString();
console.log(time + " - Rendering MyButton #" + props.id + " ...");
return (
<TouchableOpacity
style={styles.myButton}
onPress={() => {
addItem({
name: "Item #" + props.id
});
}}
>
<Text>Add</Text>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
myButton: {
width: 100,
margin: 10,
padding: 10,
textAlign: "center",
borderWidth: 1,
borderColor: "#ccc",
backgroundColor: "#e0e0e0",
borderRadius: 5
}
});
Here is the Codesandbox codes: https://codesandbox.io/s/usecontext-dependency-fpcep?file=/src/App.js
Turns out that I have to split Context into two, one that doesn’t have dependency, only to run the functions, and one that shows any value(s) real-time by adding the dependency. The same with the consumer component(s), take it out as new component and put the useContext
in there, so parent component won’t be re-rendered.