Open ArthurWangCN opened 5 months ago
这种父子通信方式也就是典型的单向数据流, 父组件通过 props 传递数据, 子组件不能直接修改 props, 而是必须通过调用父组件函数的方式告知父组件修改数据
状态提升: 在父组件中创建共同的状态、事件函数, 其中一个兄弟组件调用父组件传递过来的事件函数修改父组件中的状态, 然后父组件将状态传递给另一个兄弟组件
使用 Context:
import { createContext, useContext } from 'react';
const ThemeContext = createContext(null);
function App({ children }) {
const theme = useContext(ThemeContext);
return (<div>{theme}</div>)
}
function MyApp() {
return (
<ThemeContext.Provider value="dark">
<App />
</ThemeContext.Provider>
)
}
或使用 Redux 等状态管理工具
组件内部 state 或值完全受 prop 控制的组件
就像 antd 里 Input 组件, 可以通过 props 传一个 value 使得 Input 变为受控组件, Input 组件内部状态(值)就由 props 控制
import { Input } from 'antd';
<Input value="写死或者设置为状态值"/>
组件内部 state或值不受 props 控制的组件, 由组件内部自己管理
就像 antd 里 Input 组件, 如果不给组件传 value 值, 那么组件就是非受控组件, Input 组件内由自己管理 value, 这时如果要想拿到表单的 value 则只能通过 ref 等手段, 手动获取
注意的是: Input 组件内部, 使用了 input 标签将 value 和状态进行绑定, 那么对于 input 标签来说它是受控的, 所以受控组件只是相对
import { Input } from 'antd';
<Input/>
当组件内部值或状态和外部存在交互逻辑时, 则需要将其作为受控组件进行使用
// 类组件, 使用 createRef
this.ref = React.createRef();
<div ref={this.ref}></div>
// 函数组件, 使用 useRef const ref = React.useRef();
2. ref 回调函数方式
```js
// 类组件
bindRef = ele => {
this.bodyRef = ele;
};
<div ref={this.bindRef}></div>
// 函数组件
const bindRef = useCallback((ele) => {}, []);
<div ref={bindRef}></div>
// 会自动在 this 上绑定 bodyRef, 等于当前元素
<div ref="bodyRef"></div>
class A extends Component {}
const App = () => {
const ref = useRef()
return (<A ref={ref}/>)
}
// 子组件
const ChildComponent = forwardRef((props, ref) => {
const inputRef = useRef();
// 通过 useImperativeHandle 将子组件的方法暴露给父组件
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
},
getValue: () => {
return inputRef.current.value;
}
}));
return <input type="text" ref={inputRef} />;
});
// 父组件
const childRef = useRef();
return (
<div>
<ChildComponent ref={childRef} />
</div>
)
解释:
子组件 ChildComponent:
父组件 ParentComponent:
在 React 中如果需要渲染多个元素, 需要使用元素进行包裹, 否则将会报错。报错原因, 主要原因还是在 JSX 编译这块:
// 编译前
const dom = (
<ChildA />
<ChildB />
<ChildC />
);
// 编译后, 这样很明显是有问题的
const dom = (
React.createElement(……)
React.createElement(……)
React.createElement(……)
);
上面错误代码解决办法就是, 使用 div 等标签进行包裹, 这样就能够通过编译,但是会添加了额外节点, Fragment 出现就为了解决上面的问题, 通过 Fragment 可以将子列表分组, 最终在渲染为真实 DOM 节点时会将其忽略(不会进行渲染)。
<></>
<>
并不接受任何属性, 包括 key、ref 属性
React事件机制
什么是合成事件
React基于浏览器的事件机制实现了一套自身的事件机制,它符合W3C规范,包括事件触发、事件冒泡、事件捕获、事件合成和事件派发等
React事件的设计动机(作用):
React事件机制和原生DOM事件流有什么区别
虽然合成事件不是原生DOM事件,但它包含了原生DOM事件的引用,可以通过e.nativeEvent访问