什么是上下文Context
Context 通过组件树提供了一个传递数据的办法,从而防止了在每一个层级手动的传递 props 属性。
- 用法:在父组件上定义getChildContext办法,返回一个对象,而后它的子组件就能够通过this.context属性来获取
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
class Header extends Component{
render() {
return (
<div>
<Title/>
</div>
)
}
}
class Title extends Component{
static contextTypes={
color:PropTypes.string
}
render() {
return (
<div style={{color:this.context.color}}>
Title
</div>
)
}
}
class Main extends Component{
render() {
return (
<div>
<Content>
</Content>
</div>
)
}
}
class Content extends Component{
static contextTypes={
color: PropTypes.string,
changeColor:PropTypes.func
}
render() {
return (
<div style={{color:this.context.color}}>
Content
<button onClick={()=>this.context.changeColor('green')}>绿色</button>
<button onClick={()=>this.context.changeColor('orange')}>橙色</button>
</div>
)
}
}
class Page extends Component{
constructor() {
super();
this.state={color:'red'};
}
static childContextTypes={
color: PropTypes.string,
changeColor:PropTypes.func
}
getChildContext() {
return {
color: this.state.color,
changeColor:(color)=>{
this.setState({color})
}
}
}
render() {
return (
<div>
<Header/>
<Main/>
</div>
)
}
}
ReactDOM.render(<Page/>,document.querySelector('#root'));
React-Router 4的Switch有什么用?
Switch 通常被用来包裹 Route,用于渲染与门路匹配的第一个子 <Route>
或 <Redirect>
,它外面不能放其余元素。
如果不加 <Switch>
:
import { Route } from 'react-router-dom'
<Route path="/" component={Home}></Route>
<Route path="/login" component={Login}></Route>
Route 组件的 path 属性用于匹配门路,因为须要匹配 /
到 Home
,匹配 /login
到 Login
,所以须要两个 Route,然而不能这么写。这样写的话,当 URL 的 path 为 “/login” 时,<Route path="/" />
和<Route path="/login" />
都会被匹配,因而页面会展现 Home 和 Login 两个组件。这时就须要借助 <Switch>
来做到只显示一个匹配组件:
import { Switch, Route} from 'react-router-dom'
<Switch>
<Route path="/" component={Home}></Route>
<Route path="/login" component={Login}></Route>
</Switch>
此时,再拜访 “/login” 门路时,却只显示了 Home 组件。这是就用到了exact属性,它的作用就是准确匹配门路,常常与<Switch>
联结应用。只有当 URL 和该 <Route>
的 path 属性完全一致的状况下能力匹配上:
import { Switch, Route} from 'react-router-dom'
<Switch>
<Route exact path="/" component={Home}></Route>
<Route exact path="/login" component={Login}></Route>
</Switch>
React 中 keys 的作用是什么?
Keys 是 React 用于追踪哪些列表中元素被批改、被增加或者被移除的辅助标识。
在 React 中渲染汇合时,向每个反复的元素增加关键字对于帮忙React跟踪元素与数据之间的关联十分重要。key 应该是惟一ID,最好是 UUID 或收集项中的其余惟一字符串:
<ul>
{todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
)};
</ul>
在汇合中增加和删除我的项目时,不应用键或将索引用作键会导致奇怪的行为。
为什么虚构dom会进步性能
虚构
dom
相当于在js
和实在dom
两头加了一个缓存,利用dom diff
算法防止了没有必要的dom
操作,从而进步性能
具体实现步骤如下
- 用
JavaScript
对象构造示意 DOM 树的构造;而后用这个树构建一个真正的DOM
树,插到文档当中 - 当状态变更的时候,从新结构一棵新的对象树。而后用新的树和旧的树进行比拟,记录两棵树差别
- 把2所记录的差别利用到步骤1所构建的真正的
DOM
树上,视图就更新
虚构DOM肯定会进步性能吗?
很多人认为虚构DOM肯定会进步性能,肯定会更快,其实这个说法有点全面,因为虚构DOM尽管会缩小DOM操作,但也无奈防止DOM操作
- 它的劣势是在于diff算法和批量解决策略,将所有的DOM操作收集起来,一次性去扭转实在的DOM,但在首次渲染上,虚构DOM会多了一层计算,耗费一些性能,所以有可能会比html渲染的要慢
- 留神,虚构DOM实际上是给咱们找了一条最短,最近的门路,并不是说比DOM操作的更快,而是门路最简略
当渲染一个列表时,何为 key?设置 key 的目标是什么
Keys 会有助于 React 辨认哪些 items
扭转了,被增加了或者被移除了。Keys 应该被赋予数组内的元素以赋予(DOM)元素一个稳固的标识,抉择一个 key 的最佳办法是应用一个字符串,该字符串能惟一地标识一个列表项。很多时候你会应用数据中的 IDs 作为 keys,当你没有稳固的 IDs 用于被渲染的 items
时,能够应用我的项目索引作为渲染项的 key,但这种形式并不举荐,如果 items
能够从新排序,就会导致 re-render
变慢。
React Hooks在平时开发中须要留神的问题和起因
(1)不要在循环,条件或嵌套函数中调用Hook,必须始终在 React函数的顶层应用Hook
这是因为React须要利用调用程序来正确更新相应的状态,以及调用相应的钩子函数。一旦在循环或条件分支语句中调用Hook,就容易导致调用程序的不一致性,从而产生难以预料到的结果。
(2)应用useState时候,应用push,pop,splice等间接更改数组对象的坑
应用push间接更改数组无奈获取到新值,应该采纳析构形式,然而在class外面不会有这个问题。代码示例:
function Indicatorfilter() {
let [num,setNums] = useState([0,1,2,3])
const test = () => {
// 这里坑是间接采纳push去更新num
// setNums(num)是无奈更新num的
// 必须应用num = [...num ,1]
num.push(1)
// num = [...num ,1]
setNums(num)
}
return (
<div className='filter'>
<div onClick={test}>测试</div>
<div>
{num.map((item,index) => ( <div key={index}>{item}</div>
))} </div>
</div>
)
}
class Indicatorfilter extends React.Component<any,any>{
constructor(props:any){
super(props)
this.state = {
nums:[1,2,3]
}
this.test = this.test.bind(this)
}
test(){
// class采纳同样的形式是没有问题的
this.state.nums.push(1)
this.setState({
nums: this.state.nums
})
}
render(){
let {nums} = this.state
return(
<div>
<div onClick={this.test}>测试</div>
<div>
{nums.map((item:any,index:number) => ( <div key={index}>{item}</div>
))} </div>
</div>
)
}
}
(3)useState设置状态的时候,只有第一次失效,前期须要更新状态,必须通过useEffect
TableDeail是一个公共组件,在调用它的父组件外面,咱们通过set扭转columns的值,认为传递给TableDeail 的 columns是最新的值,所以tabColumn每次也是最新的值,然而理论tabColumn是最开始的值,不会随着columns的更新而更新:
const TableDeail = ({ columns,}:TableData) => {
const [tabColumn, setTabColumn] = useState(columns)
}
// 正确的做法是通过useEffect扭转这个值
const TableDeail = ({ columns,}:TableData) => {
const [tabColumn, setTabColumn] = useState(columns)
useEffect(() =>{setTabColumn(columns)},[columns])
}
(4)善用useCallback
父组件传递给子组件事件句柄时,如果咱们没有任何参数变动可能会选用useMemo。然而每一次父组件渲染子组件即便没变动也会跟着渲染一次。
(5)不要滥用useContext
能够应用基于 useContext 封装的状态管理工具。
参考 前端进阶面试题具体解答
能够应用TypeScript写React利用吗?怎么操作?
(1)如果还未创立 Create React App 我的项目
- 间接创立一个具备 typescript 的 Create React App 我的项目:
npx create-react-app demo --typescript
(2)如果曾经创立了 Create React App 我的项目,须要将 typescript 引入到已有我的项目中
- 通过命令将 typescript 引入我的项目:
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
- 将我的项目中任何 后缀名为 ‘.js’ 的 JavaScript 文件重命名为 TypeScript 文件即后缀名为 ‘.tsx’(例如 src/index.js 重命名为 src/index.tsx )
React setState 调用的原理
具体的执行过程如下(源码级解析):
- 首先调用了
setState
入口函数,入口函数在这里就是充当一个散发器的角色,依据入参的不同,将其散发到不同的性能函数中去;
ReactComponent.prototype.setState = function (partialState, callback) {
this.updater.enqueueSetState(this, partialState);
if (callback) {
this.updater.enqueueCallback(this, callback, 'setState');
}
};
enqueueSetState
办法将新的state
放进组件的状态队列里,并调用enqueueUpdate
来解决将要更新的实例对象;
enqueueSetState: function (publicInstance, partialState) {
// 依据 this 拿到对应的组件实例
var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState');
// 这个 queue 对应的就是一个组件实例的 state 数组
var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);
queue.push(partialState);
// enqueueUpdate 用来解决以后的组件实例
enqueueUpdate(internalInstance);
}
- 在
enqueueUpdate
办法中引出了一个要害的对象——batchingStrategy
,该对象所具备的isBatchingUpdates
属性间接决定了当下是要走更新流程,还是应该排队期待;如果轮到执行,就调用batchedUpdates
办法来间接发动更新流程。由此能够揣测,batchingStrategy
或者正是 React 外部专门用于管控批量更新的对象。
function enqueueUpdate(component) {
ensureInjected();
// 留神这一句是问题的要害,isBatchingUpdates标识着以后是否处于批量创立/更新组件的阶段
if (!batchingStrategy.isBatchingUpdates) {
// 若以后没有处于批量创立/更新组件的阶段,则立刻更新组件
batchingStrategy.batchedUpdates(enqueueUpdate, component);
return;
}
// 否则,先把组件塞入 dirtyComponents 队列里,让它“再等等”
dirtyComponents.push(component);
if (component._updateBatchNumber == null) {
component._updateBatchNumber = updateBatchNumber + 1;
}
}
留神:batchingStrategy
对象能够了解为“锁管理器”。这里的“锁”,是指 React 全局惟一的 isBatchingUpdates
变量,isBatchingUpdates
的初始值是 false
,意味着“以后并未进行任何批量更新操作”。每当 React 调用 batchedUpdate
去执行更新动作时,会先把这个锁给“锁上”(置为 true
),表明“当初正处于批量更新过程中”。当锁被“锁上”的时候,任何须要更新的组件都只能临时进入 dirtyComponents
里排队等待下一次的批量更新,而不能随便“插队”。此处体现的“工作锁”的思维,是 React 面对大量状态依然可能实现有序分批解决的基石。
在React中组件的this.state和setState有什么区别?
this.state通常是用来初始化state的,this.setState是用来批改state值的。如果初始化了state之后再应用this.state,之前的state会被笼罩掉,如果应用this.setState,只会替换掉相应的state值。所以,如果想要批改state的值,就须要应用setState,而不能间接批改state,间接批改state之后页面是不会更新的。
React中发动网络申请应该在哪个生命周期中进行?为什么?
对于异步申请,最好放在componentDidMount中去操作,对于同步的状态扭转,能够放在componentWillMount中,个别用的比拟少。
如果认为在componentWillMount里发动申请能提前取得后果,这种想法其实是谬误的,通常componentWillMount比componentDidMount早不了多少微秒,网络上任何一点提早,这一点差别都可忽略不计。
react的生命周期: constructor() -> componentWillMount() -> render() -> componentDidMount()
下面这些办法的调用是有秩序的,由上而下顺次调用。
- constructor被调用是在组件筹备要挂载的最开始,此时组件尚未挂载到网页上。
- componentWillMount办法的调用在constructor之后,在render之前,在这办法里的代码调用setState办法不会触发从新render,所以它个别不会用来作加载数据之用。
- componentDidMount办法中的代码,是在组件曾经齐全挂载到网页上才会调用被执行,所以能够保证数据的加载。此外,在这办法中调用setState办法,会触发从新渲染。所以,官网设计这个办法就是用来加载内部数据用的,或解决其余的副作用代码。与组件上的数据无关的加载,也能够在constructor里做,但constructor是做组件state初绐化工作,并不是做加载数据这工作的,constructor里也不能setState,还有加载的工夫太长或者出错,页面就无奈加载进去。所以有副作用的代码都会集中在componentDidMount办法里。
总结:
- 跟服务器端渲染(同构)有关系,如果在componentWillMount外面获取数据,fetch data会执行两次,一次在服务器端一次在客户端。在componentDidMount中能够解决这个问题,componentWillMount同样也会render两次。
- 在componentWillMount中fetch data,数据肯定在render后能力达到,如果遗记了设置初始状态,用户体验不好。
- react16.0当前,componentWillMount可能会被执行屡次。
constructor 为什么不先渲染?
由ES6的继承规定得悉,不论子类写不写constructor,在new实例的过程都会给补上constructor。
所以:constructor钩子函数并不是不可短少的,子组件能够在一些状况略去。比方不本人的state,从props中获取的状况
类组件和函数组件有何不同?
解答
在 React 16.8版本(引入钩子)之前,应用基于类的组件来创立须要保护外部状态或利用生命周期办法的组件(即componentDidMount
和shouldComponentUpdate
)。基于类的组件是 ES6 类,它扩大了 React 的 Component 类,并且至多实现了render()
办法。
类组件:
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
函数组件是无状态的(同样,小于 React 16.8版本),并返回要出现的输入。它们渲染 UI 的首选只依赖于属性,因为它们比基于类的组件更简略、更具性能。
函数组件:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
留神:在 React 16.8版本中引入钩子意味着这些区别不再实用(请参阅14和15题)。
setState 是同步异步?为什么?实现原理?
1. setState是同步执行的
setState是同步执行的,然而state并不一定会同步更新
2. setState在React生命周期和合成事件中批量笼罩执行
在React的生命周期钩子和合成事件中,屡次执行setState,会批量执行
具体表现为,屡次同步执行的setState,会进行合并,相似于Object.assign,雷同的key,前面的会笼罩后面的
当遇到多个setState调用时候,会提取单次传递setState的对象,把他们合并在一起造成一个新的
繁多对象,并用这个繁多的对象去做setState的事件,就像Object.assign的对象合并,后一个
key值会笼罩后面的key值
通过React 解决的事件是不会同步更新 this.state的. 通过 addEventListener || setTimeout/setInterval 的形式解决的则会同步更新。
为了合并setState,咱们须要一个队列来保留每次setState的数据,而后在一段时间后执行合并操作和更新state,并清空这个队列,而后渲染组件。
React 高阶组件是什么,和一般组件有什么区别,实用什么场景
官网解释∶
高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 本身不是 React API 的一部分,它是一种基于 React 的组合个性而造成的设计模式。
高阶组件(HOC)就是一个函数,且该函数承受一个组件作为参数,并返回一个新的组件,它只是一种组件的设计模式,这种设计模式是由react本身的组合性质必然产生的。咱们将它们称为纯组件,因为它们能够承受任何动静提供的子组件,但它们不会批改或复制其输出组件中的任何行为。
// hoc的定义
function withSubscription(WrappedComponent, selectData) {
return class extends React.Component {
constructor(props) {
super(props);
this.state = {
data: selectData(DataSource, props)
};
}
// 一些通用的逻辑解决
render() {
// ... 并应用新数据渲染被包装的组件!
return <WrappedComponent data={this.state.data} {...this.props} />;
}
};
// 应用
const BlogPostWithSubscription = withSubscription(BlogPost,
(DataSource, props) => DataSource.getBlogPost(props.id));
1)HOC的优缺点
- 长处∶ 逻辑服用、不影响被包裹组件的外部逻辑。
- 毛病∶hoc传递给被包裹组件的props容易和被包裹后的组件重名,进而被笼罩
2)实用场景
- 代码复用,逻辑形象
- 渲染劫持
- State 形象和更改
- Props 更改
3)具体利用例子
- 权限管制: 利用高阶组件的 条件渲染 个性能够对页面进行权限管制,权限管制个别分为两个维度:页面级别和 页面元素级别
// HOC.js
function withAdminAuth(WrappedComponent) {
return class extends React.Component {
state = {
isAdmin: false,
}
async UNSAFE_componentWillMount() {
const currentRole = await getCurrentUserRole();
this.setState({
isAdmin: currentRole === 'Admin',
});
}
render() {
if (this.state.isAdmin) {
return <WrappedComponent {...this.props} />;
} else {
return (<div>您没有权限查看该页面,请分割管理员!</div>);
}
}
};
}
// pages/page-a.js
class PageA extends React.Component {
constructor(props) {
super(props);
// something here...
}
UNSAFE_componentWillMount() {
// fetching data
}
render() {
// render page with data
}
}
export default withAdminAuth(PageA);
// pages/page-b.js
class PageB extends React.Component {
constructor(props) {
super(props);
// something here...
}
UNSAFE_componentWillMount() {
// fetching data
}
render() {
// render page with data
}
}
export default withAdminAuth(PageB);
- 组件渲染性能追踪: 借助父组件子组件生命周期规定捕捉子组件的生命周期,能够不便的对某个组件的渲染工夫进行记录∶
class Home extends React.Component {
render() {
return (<h1>Hello World.</h1>);
}
}
function withTiming(WrappedComponent) {
return class extends WrappedComponent {
constructor(props) {
super(props);
this.start = 0;
this.end = 0;
}
UNSAFE_componentWillMount() {
super.componentWillMount && super.componentWillMount();
this.start = Date.now();
}
componentDidMount() {
super.componentDidMount && super.componentDidMount();
this.end = Date.now();
console.log(`${WrappedComponent.name} 组件渲染工夫为 ${this.end - this.start} ms`);
}
render() {
return super.render();
}
};
}
export default withTiming(Home);
留神:withTiming 是利用 反向继承 实现的一个高阶组件,性能是计算被包裹组件(这里是 Home 组件)的渲染工夫。
- 页面复用
const withFetching = fetching => WrappedComponent => {
return class extends React.Component {
state = {
data: [],
}
async UNSAFE_componentWillMount() {
const data = await fetching();
this.setState({
data,
});
}
render() {
return <WrappedComponent data={this.state.data} {...this.props} />;
}
}
}
// pages/page-a.js
export default withFetching(fetching('science-fiction'))(MovieList);
// pages/page-b.js
export default withFetching(fetching('action'))(MovieList);
// pages/page-other.js
export default withFetching(fetching('some-other-type'))(MovieList);
React Hooks 和生命周期的关系?
函数组件 的实质是函数,没有 state 的概念的,因而不存在生命周期一说,仅仅是一个 render 函数而已。
然而引入 Hooks 之后就变得不同了,它能让组件在不应用 class 的状况下领有 state,所以就有了生命周期的概念,所谓的生命周期其实就是 useState
、 useEffect()
和 useLayoutEffect()
。
即:Hooks 组件(应用了Hooks的函数组件)有生命周期,而函数组件(未应用Hooks的函数组件)是没有生命周期的。
上面是具体的 class 与 Hooks 的生命周期对应关系:
constructor
:函数组件不须要构造函数,能够通过调用**useState 来初始化 state**
。如果计算的代价比拟低廉,也能够传一个函数给useState
。
const [num, UpdateNum] = useState(0)
getDerivedStateFromProps
:个别状况下,咱们不须要应用它,能够在渲染过程中更新 state,以达到实现getDerivedStateFromProps
的目标。
function ScrollView({row}) {
let [isScrollingDown, setIsScrollingDown] = useState(false);
let [prevRow, setPrevRow] = useState(null);
if (row !== prevRow) {
// Row 自上次渲染以来产生过扭转。更新 isScrollingDown。
setIsScrollingDown(prevRow !== null && row > prevRow);
setPrevRow(row);
}
return `Scrolling down: ${isScrollingDown}`;
}
React 会立刻退出第一次渲染并用更新后的 state 从新运行组件以防止消耗太多性能。
shouldComponentUpdate
:能够用**React.memo**
包裹一个组件来对它的props
进行浅比拟
const Button = React.memo((props) => { // 具体的组件});
留神:**React.memo 等效于 **
`PureComponent,它只浅比拟 props。这里也能够应用
useMemo` 优化每一个节点。
render
:这是函数组件体自身。componentDidMount
,componentDidUpdate
:useLayoutEffect
与它们两的调用阶段是一样的。然而,咱们举荐你一开始先用 useEffect,只有当它出问题的时候再尝试应用useLayoutEffect
。useEffect
能够表白所有这些的组合。
// componentDidMount
useEffect(()=>{
// 须要在 componentDidMount 执行的内容
}, [])
useEffect(() => {
// 在 componentDidMount,以及 count 更改时 componentDidUpdate 执行的内容
document.title = `You clicked ${count} times`;
return () => {
// 须要在 count 更改时 componentDidUpdate(先于 document.title = ... 执行,恪守先清理后更新)
// 以及 componentWillUnmount 执行的内容
} // 当函数中 Cleanup 函数会依照在代码中定义的程序先后执行,与函数自身的个性无关
}, [count]); // 仅在 count 更改时更新
请记得 React 会期待浏览器实现画面渲染之后才会提早调用 ,因而会使得额定操作很不便
componentWillUnmount
:相当于useEffect
外面返回的cleanup
函数
// componentDidMount/componentWillUnmount
useEffect(()=>{
// 须要在 componentDidMount 执行的内容
return function cleanup() {
// 须要在 componentWillUnmount 执行的内容
}
}, [])
componentDidCatch
andgetDerivedStateFromError
:目前还没有这些办法的 Hook 等价写法,但很快会加上。
class 组件 | Hooks 组件 |
---|---|
constructor | useState |
getDerivedStateFromProps | useState 外面 update 函数 |
shouldComponentUpdate | useMemo |
render | 函数自身 |
componentDidMount | useEffect |
componentDidUpdate | useEffect |
componentWillUnmount | useEffect 外面返回的函数 |
componentDidCatch | 无 |
getDerivedStateFromError | 无 |
React 的工作原理
React 会创立一个虚构 DOM(virtual DOM)。当一个组件中的状态扭转时,React 首先会通过 “diffing” 算法来标记虚构 DOM 中的扭转,第二步是调节(reconciliation),会用 diff 的后果来更新 DOM。
React中的props为什么是只读的?
this.props
是组件之间沟通的一个接口,原则上来讲,它只能从父组件流向子组件。React具备浓厚的函数式编程的思维。
提到函数式编程就要提一个概念:纯函数。它有几个特点:
- 给定雷同的输出,总是返回雷同的输入。
- 过程没有副作用。
- 不依赖内部状态。
this.props
就是吸取了纯函数的思维。props的不能够变性就保障的雷同的输出,页面显示的内容是一样的,并且不会产生副作用
React 事件机制
<div onClick={this.handleClick.bind(this)}>点我</div>
React并不是将click事件绑定到了div的实在DOM上,而是在document处监听了所有的事件,当事件产生并且冒泡到document处的时候,React将事件内容封装并交由真正的处理函数运行。这样的形式不仅仅缩小了内存的耗费,还能在组件挂在销毁时对立订阅和移除事件。
除此之外,冒泡到document上的事件也不是原生的浏览器事件,而是由react本人实现的合成事件(SyntheticEvent)。因而如果不想要是事件冒泡的话应该调用event.preventDefault()办法,而不是调用event.stopProppagation()办法。 JSX 上写的事件并没有绑定在对应的实在 DOM 上,而是通过事件代理的形式,将所有的事件都对立绑定在了 document
上。这样的形式不仅缩小了内存耗费,还能在组件挂载销毁时对立订阅和移除事件。
另外冒泡到 document
上的事件也不是原生浏览器事件,而是 React 本人实现的合成事件(SyntheticEvent)。因而咱们如果不想要事件冒泡的话,调用 event.stopPropagation
是有效的,而应该调用 event.preventDefault
。
实现合成事件的目标如下:
- 合成事件首先抹平了浏览器之间的兼容问题,另外这是一个跨浏览器原生事件包装器,赋予了跨浏览器开发的能力;
- 对于原生浏览器事件来说,浏览器会给监听器创立一个事件对象。如果你有很多的事件监听,那么就须要调配很多的事件对象,造成高额的内存调配问题。然而对于合成事件来说,有一个事件池专门来治理它们的创立和销毁,当事件须要被应用时,就会从池子中复用对象,事件回调完结后,就会销毁事件对象上的属性,从而便于下次复用事件对象。
hooks父子传值
父传子
在父组件中用useState申明数据
const [ data, setData ] = useState(false)
把数据传递给子组件
<Child data={data} />
子组件接管
export default function (props) {
const { data } = props
console.log(data)
}
子传父
子传父能够通过事件办法传值,和父传子有点相似。
在父组件中用useState申明数据
const [ data, setData ] = useState(false)
把更新数据的函数传递给子组件
<Child setData={setData} />
子组件中触发函数更新数据,就会间接传递给父组件
export default function (props) {
const { setData } = props
setData(true)
}
如果存在多个层级的数据传递,也可按照此办法顺次传递
// 多层级用useContext
const User = () => {
// 间接获取,不必回调
const { user, setUser } = useContext(UserContext);
return <Avatar user={user} setUser={setUser} />;
};
高阶组件存在的问题
- 静态方法失落(必须将静态方法做拷贝)
refs
属性不能透传(如果你向一个由高阶组件创立的组件的元素增加ref
援用,那么ref
指向的是最外层容器组件实例的,而不是被包裹的WrappedComponent
组件。)- 反向继承不能保障残缺的子组件树被解析
React 组件有两种模式,别离是 class 类型和 function 类型(无状态组件)。
咱们晓得反向继承的渲染劫持能够管制 WrappedComponent
的渲染过程,也就是说这个过程中咱们能够对 elements tree
、 state
、 props
或 render()
的后果做各种操作。
然而如果渲染 elements tree
中蕴含了 function 类型的组件的话,这时候就不能操作组件的子组件了。
发表回复