总结一下React中组件传值。组件分为函数组件和类组件。组件传值分为父子传值和兄弟传值。
一、父子传值
父组件传值给子组件是较为常见的组件传值方式。
function Father(){
return(
<div className="c-father" >
<Son text="theme" />
</div>
)
}
function Son(props){
return(
<div>
<div className="c-father_son">{props.text}</div>
</div>
)
}
ReactDOM.render(
<Father />,
document.getElementById("test")
)
子组件传值给父组件,需要父组件首先将一个回调函数作为props传给子组件,子组件通过回调函数传值给父组件。
function Father(){
const [color,setColor] = React.useState(false);
const changeColor = (isChange)=>{
setColor(isChange);
}
return(
<div className="c-father" style={{backgroundColor:color?"pink":"yellow"}}>
<Son text="theme" color={changeColor} />
</div>
)
}
function Son(props){
return(
<div>
<div className="c-father_son">{props.text}</div>
<button onClick={()=>{props.color(true)}}>切换颜色</button>
</div>
)
}
ReactDOM.render(
<Father />,
document.getElementById("test")
)
二、兄弟传值
兄弟传值其实和父子传值类似,就是子传父和父传子的结合。父组件作为兄弟组件传值的中介。
function Father(){
const [color,setColor] = React.useState(false);
const [text,setText] = React.useState();
const changeColor = (isChange)=>{
setColor(isChange);
}
const showText = (content)=>{
setText(content);
}
return(
<div className="c-father" style={{backgroundColor:color?"pink":"yellow"}}>
<Son text="theme" color={changeColor} showText={showText}/>
<AnotherSon text={text}/>
</div>
)
}
function Son(props){
return(
<div>
<div className="c-father_son">{props.text}</div>
<button onClick={()=>{props.color(true)}}>切换颜色</button>
<button onClick={()=>{props.showText("我要给兄弟传值")}}>我要传值</button>
</div>
)
}
function AnotherSon(props){
return(
<div>{props.text}</div>
)
}
ReactDOM.render(
<Father />,
document.getElementById("test")
)
三、补充
1.关于父传子,如果目的子组件在组件嵌套的深层,直接用props传值是不实际的,可以考虑用context。
const statusContext = React.createContext("good");
function Father(){
const [color,setColor] = React.useState(false);
const [text,setText] = React.useState();
const changeColor = (isChange)=>{
setColor(isChange);
}
const showText = (content)=>{
setText(content);
}
return(
<div className="c-father" style={{backgroundColor:color?"pink":"yellow"}}>
<statusContext.Provider value="nice">
<Son text="theme" color={changeColor} showText={showText}/>
</statusContext.Provider>
{/*<AnotherSon text={text}/>*/}
</div>
)
}
function Son(props){
return(
<div>
<AnotherSon />
<div className="c-father_son">{props.text}</div>
<button onClick={()=>{props.color(true)}}>切换颜色</button>
<button onClick={()=>{props.showText("我要给兄弟传值")}}>我要传值</button>
</div>
)
}
function AnotherSon(props){
const status = React.useContext(statusContext);
return(
<div>
{status}
<div>{props.text}</div>
</div>
)
}
ReactDOM.render(
<Father />,
document.getElementById("test")
)
React创建context对象,在目的子组件利用useContext接收context对象,目的子组件会根据离它最近的Provider提供的value值发生变化。
2.关于子组件传值给父组件或者兄弟组件间传值,除了用props+回调函数之外,也可以利用ref解决
const statusContext = React.createContext("good");
function Father(){
const [color,setColor] = React.useState(false);
const [text,setText] = React.useState();
const changeColor = (isChange)=>{
setColor(isChange);
}
const sonRef = React.createRef();
const handleClick = ()=>{
sonRef.current.output("今天天气预报");
}
return(
<div className="c-father" style={{backgroundColor:color?"pink":"yellow"}}>
<statusContext.Provider value="nice">
<Son text="theme" color={changeColor} clickEve={handleClick}/>
</statusContext.Provider>
<AnotherSon ref={sonRef}/>
</div>
)
}
function Son(props){
return(
<div>
<div className="c-father_son">{props.text}</div>
<button onClick={()=>{props.color(true)}}>切换颜色</button>
<button onClick={()=>{props.clickEve()}}>我要传值</button>
</div>
)
}
const AnotherSon = React.forwardRef((props,ref)=>{
const [test,setTest] = React.useState("");
React.useImperativeHandle(ref,()=>({
output:(warn)=>{
console.log("this is",warn);
setTest(warn);
}
}))
//console.log(ref)
return(
<div ref={ref}>{test}</div>
)
})
ReactDOM.render(
<Father />,
document.getElementById("test")
)
首先利用forwardRef创建目的子组件,将ref给到具体DOM节点。在父组件创建ref,并给到目的子组件。目的子组件利用useImperativeHandle向父组件暴露自定义属性,父组件创建方法调用目的子组件的属性,并将方法传给作为发送数据的子组件。
除了ref,还有useReducer,这和react的redux有点类似。利用useContext将reducer的state转换为一组共有父组件的子组件的共有变量。
const statusContext = React.createContext("good");
const initState = {count:0};
function reducer(state,action){
console.log(action.type)
switch(action.type){
case "plus":return{count:state.count+1};break;
case "minus":return{count:state.count-1};break;
default:throw new Error();
}
}
function Father(){
const [text,setText] = React.useState();
const [state,dispatch] = React.useReducer(reducer,initState);
const showText = (content)=>{
setText(content);
}
const sonRef = React.createRef();
const handleClick = ()=>{
sonRef.current.output("今天天气预报");
}
return(
<div className="c-father" style={{backgroundColor:color?"pink":"yellow"}}>
<statusContext.Provider value={{count:state.count,dispatch:dispatch}}>
//将state和dispatch一起分发下去
<Son text="theme" showText={showText} clickEve={handleClick}/>
<AnotherSon text={text} ref={sonRef}/>
</statusContext.Provider>
</div>
)
}
function Son(props){
const {dispatch} = React.useContext(statusContext);
//console.log(dispatch)
return(
<div>
<div className="c-father_son">{props.text}</div>
<button onClick={()=>{dispatch({type:"plus"})}}>切换数字</button>
<button onClick={()=>{props.clickEve()}}>我要传值</button>
</div>
)
}
const AnotherSon = React.forwardRef((props,ref)=>{
const [test,setTest] = React.useState("");
const {count} = React.useContext(statusContext);
React.useImperativeHandle(ref,()=>({
output:(warn)=>{
console.log("this is",warn);
setTest(warn);
}
}))
console.log(count)
return(
<div ref={ref}>{count}</div>
)
})
ReactDOM.render(
<Father />,
document.getElementById("test")
)