preface
The most common problems or oddities in developing applications with React come from component communication requirements. This article focuses on two common approaches, props and Context, and a special approach, component functionalization
The code in this article has function components as the discussion benchmark, using React Hook to implement.
The body of the
Use Props to implement component communication
Using Props is the most common way, and the most problematic way, why? Let’s take a look at the code in the following two cases
Props implements parent-child component communication
function Child(props) {
const { state, setState } = props;
const onButtonClick = () = >{
setState('Posterity knows')}return (<><div>{state}</div><button onClick={onButtonClick}>Posterity knows</button></>);
}
function Father() {
const [state, setState] = useState("state");
return (
<div>
<Child state={state} setState={setState}/>
</div>
);
}
Copy the code
If your component structure of father and son are standard structure, namely the parent component with a straton component, then the Props is a lightweight solution, but the actual development, I’ve seen a lot of components of the family also use Props to transfer, especially deeply nested structure of transfer, then the parent components directly promoted to ancestors
function Child3(){
return(
<div>
<Child2 />
</div>)}function Child2(){
return(
<div>
<Child1 />
</div>)}function Child1(){
return(
<div></div>
)
}
fucntion Father(){
return(
<div>
<Child3 />
</div
)
}
Copy the code
To pass the state in Father to Child1, you need to layer through 2 layers of components using Props. You’ll notice that this has a similar effect to some poorly written functions
function clac1(father1){
// CLac1 requires arguments from father1
}
function clac2(father1){
clac1(father1)
}
fucntion clac3(fatcher1){
clac2(father1)
}
function father(){
clac3(fatcher1)
}
Copy the code
Clac2 and CLAC3 may both implement some of their own logic, but in the larger logic chain, they take responsibility for passing father1 into CLAC1, which is a typical anti-pattern. But we used it a lot in our React component.
Props implements communication between components
Cross – component communication (Props) supports cross – component communication (Props). Cross – component communication (Props) also needs a bridge.
function Channel() {
const [stateA, setStateA] = useState("A");
const [stateB, setStateB] = useState("B");
return (
<>
<ComA stateA={stateA} setStateB={setStateB} setStateA={setStateA} />
<h6>The divider</h6>
<ComB stateB={stateB} setStateA={setStateA} setStateB={setStateB} />
</>
);
}
function ComA(props) {
const onButtonClick = () = > {
props.setStateB(props.stateA);
};
const onResetButtonClick = () = > {
props.setStateA("A");
};
return (
<>
<div>{props.stateA}</div>
<button onClick={onButtonClick}>Change B into A</button>
<button onClick={onResetButtonClick}>Restore A</button>
</>
);
}
function ComB(props) {
const onButtonClick = () = > {
props.setStateA(props.stateB);
};
const onResetButtonClick = () = > {
props.setStateB("B");
};
return (
<>
<div>{props.stateB}</div>
<button onClick={onButtonClick}>Change A into B</button>
<button onClick={onResetButtonClick}>Reduction of B</button>
</>
);
}
Copy the code
This example is going to be a bit complicated and may not look very intuitive from the code, so let’s look at a short screen recording
It’s complicated enough to use Props for cross-component communication with just two states. If you consider that you need to reuse one of ComB, because of the characteristics of Props, you need to wear a Channel, which is equivalent to wearing ComA. So you go from reusing one widget to relying on a whole bunch of stuff. How often does that happen in your work?
Look at the Props and look at the Context
Context is used for component communication
Context is a bit more complex than Props for simple parent-child structures. Let’s see what happens to family components
A family component is one in which components are nested more than three layers, forming a very large nested structure, like a thriving family, with several generations living together and closely related to each other.
Let’s look at the code
const Context = React.createContext();
function Child(props) {
const { state, setState } = useContext(Context);
const onButtonClick = () = > {
setState("Posterity knows");
};
return (
<>
<div>{state}</div>
<button onClick={onButtonClick}>Posterity knows</button>
</>
);
}
function Child1() {
return (
<div>
<Child />
</div>
);
}
function Ancestor() {
const [state, setState] = useState("state");
return (
<Context.Provider value={{ state.setState}} >
<div>
<Child1 />
</div>
</Context.Provider>
);
}
Copy the code
You can see that using React. CreateContext to create a special context component avoids the problems of Props nested passes. By analogy with functions… Something like that
const context = {}
function father(){
context.father1 = 0
}
function child1(){
const father1 = context.father1
}
Copy the code
The only difference is that you don’t need to set up a Channel for the components that are communicating to manually pass Props
The problem with Context is that Context relies on a particular component, and because of its convenience it can lead to abuse, and the code ends up there
Context1.Provider
Context2.Provider
Context3.Provider
...
Copy the code
So is there a better solution to overcome the complexity of Props passthrough while avoiding the modification of the component structure by Context?
My idea is to functionalize the function component and create a Context outside of the React Context that is independent of the structure of the component to look at the code
import React from "react";
import createStore from "structured-react-hook";
const useStore = createStore({
initState: {
text: "state"
},
controller: {
onButtonClick() {
this.rc.setText("Posterity knows"); }},view: {
renderChild() {
return (
<>
<div>{this.state.text}</div>
<button onClick={this.controller.onButtonClick}>Posterity knows</button>
</>
);
},
renderFather() {
return <div>{this.view.renderChild()}</div>; }}});function AncestorStructured() {
const store = useStore();
return <div>{store.view.renderFather()}</div>;
}
Copy the code
The same effect can be achieved by creating renderChild and renderFather functions for the Child and Father components, and then creating a shared this Context for these functions instead of the React Context.
In this mechanism, the function component is only the parent of the topmost component, and the internal child components do not need to rely on the props and context to communicate with each other, either vertically or horizontally, unless you build multiple stores.
The latter
Project reference
structured-react-hook
Structurally React-hook: “Authentically easy to Maintain and Expand” components using Structurally React-Hook