面向初学者的高阶组件介绍
前言写这篇文章的起因是其他关于高阶组件(Higher-Order Components)的文章,包含官方文档,都令初学者感到相当困惑。我知道有高阶组件这样一个东西,但不知道它到底有什么用。所以,想通过一篇文章来对高阶组件有一个更好的理解。 在此之前,我们需要先来讲一下 JavaScript 中的函数。 ES6 箭头函数简介接下来将提供一些箭头函数的简单示例,如果之前没有使用过,可以认为它们与普通函数基本一致。下面的代码会展示箭头函数与普通函数的区别。 function () { return 42 } // same as: () => 42 // same as: () => { return 42 } function person(name) { return { name: name } } // same as: (name) => { return { name: name } } 阅读 MDN 的箭头函数文档 了解更多信息。 作为值的函数与部分调用就像是数字、字符串、布尔值 一样,函数也是值,意味着可以像传递其他数据一样传递函数,可以将函数作为参数传递给另外一个函数。 const execute = (someFunction) => someFunction() execute(() => alert('Executed')) 也可以在在函数中返回一个函数: const getOne = () => () => 1 getOne()() 之所以在 const getOne = () => () => 1 getOne //=> () => () => 1 getOne() //=> () => 1 getOne()() //=> 1 从函数返回函数可以帮助我们追踪初始输入函数。例如,下面的函数接受一个数字作为参数,并返回一个将该参数乘以新参数的函数: const multiply = (x) => (y) => x * y multiply(5)(20) 这个示例跟上述 const multiply = (x) => (y) => x * y multiply //=> (x) => (y) => x * y multiply(5) //=> (y) => 5 * y multiply(5)(20) //=> 5 * 20 在只传入一个参数调用 const multiply = (x) => (y) => x * y const multiplyByFive = multiply(5) const multiplyBy100 = multiply(100) multiplyByFive(20) //=> 100 multiply(5)(20) //=> 100 multiplyBy100(5) //=> 500 multiply(100)(5) //=> 500 一开始看起来似乎没什么用,但是,通过部分调用这种方式可以编写可读性更高,更易于理解的代码。举个例子,可以用一种更清晰的方式来代替 style-components 的函数插入语法。 // before const Button = styled.button` background-color: ${({ theme }) => theme.bgColor} color: ${({ theme }) => theme.textColor} ` <Button theme={themes.primary}>Submit</Button> // after const fromTheme = (prop) => ({ theme }) => theme[prop] const Button = styled.button` background-color: ${fromTheme("bgColor")} color: ${fromTheme("textColor")} ` <Button theme={themes.primary}>Submit</Button> 我们创建一个接受一个字符串作为参数的函数 const fromTheme = (prop) => ({ theme }) => theme[prop] const backgroundColor = fromTheme("bgColor") const textColor = fromTheme("textColor") const Button = styled.button` background-color: ${backgroundColor} color: ${textColor} ` <Button theme={themes.primary}>Submit</Button> 高阶函数高阶函数的定义是,接受函数作为参数的函数。如果曾经使用过类似 map 这样的函数,可能已经很熟悉高阶函数。如果不熟悉 map,它是一个数组遍历的方法,接受一个函数作为参数应用到数组中的每个元素。例如,可以像这样对一个数组作平方: const square = (x) => x * x [1,2,3].map(square) //=> [ 1,4,9 ] 可以实现一个我们自己的 const map = (fn,array) => { const mappedArray = [] for (let i = 0; i < array.length; i++) { mappedArray.push( // apply fn with the current element of the array fn(array[i]) ) } return mappedArray } 然后再使用我们的 map 版本来对一个数组作平方: const square = (x) => x * x console.log(map(square,[1,3,5])) //=> [ 1,9,16,25 ]
或者是返回一个 const HeroList = ({ heroes }) => ( <ul> {map((hero) => ( <li key={hero}>{hero}</li> ),heroes)} </ul> ) <HeroList heroes=[ "Wonder Woman","Black Widow","Spider Man","Storm","Deadpool" ]/> /*=> ( <ul> <li>Wonder Woman</li> <li>Black Widow</li> <li>Spider Man</li> <li>Storm</li> <li>Deadpool</li> </ul> )*/ 高阶组件我们知道,高阶函数是接受函数作为参数的函数。在 React 中,任何返回 JSX 的函数都被称为无状态函数组件,简称为函数组件。基本的函数组件如下所示: const Title = (props) => <h1>{props.children}</h1> <Title>Higher-Order Components(HOCs) for React Newbies</Title> //=> <h1>Higher-Order Components(HOCs) for React Newbies</h1> 高阶组件则是接受组件作为参数并返回组件的函数。如何使用传入组件完全取决于你,甚至可以完全忽视它: // Technically an HOC const ignore = (anything) => (props) => <h1>:)</h1> const IgnoreHeroList = ignore(HeroList) <IgnoreHeroList /> //=> <h1>:)</h1> 可以编写一个将输入转换成大写的 HOC: const yell = (PassedComponent) => ({ children,...props }) => <PassedComponent {...props}> {children.toUpperCase()}! </PassedComponent> const Title = (props) => <h1>{props.children}</h1> const AngryTitle = yell(Title) <AngryTitle>Whatever</AngryTitle> //=> <h1>WHATEVER!</h1> 你也可以返回一个有状态组件,因为 JavaScript 中的类不过是函数的语法糖。这样就可以使用到 React 生命周期的方法,比如 const withGists = (PassedComponent) => class WithGists extends React.Component { state = { gists: [] } componentDidMount() { fetch("https://api.github.com/gists/public") .then((r) => r.json()) .then((gists) => this.setState({ gists: gists })) } render() { return ( <PassedComponent {...this.props} gists={this.state.gists} /> ) } } const Gists = ({ gists }) => ( <pre>{JSON.stringify(gists,null,2)}</pre> ) const GistsList = withGists(Gists) <GistsList /> //=> Before api request finishes: // <Gists gists={[]} /> // //=> After api request finishes: // <Gists gists={[ // { /* … */ },// { /* … */ },// { /* … */ } // ]} />
结论:高阶组件是(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |