那个时候刚学react,不知道面试官说的元素是什么,如今知道了,就是虚拟dom嘛。。。html
React 元素(React element)react
它是 React 中最小基本单位,咱们可使用 JSX 语法轻松地建立一个 React 元素:面试
const element = <div className="element">I'm element</div> 复制代码
React 元素不是真实的 DOM 元素,它仅仅是 js 的普通对象(plain objects),因此也没办法直接调用 DOM 原生的 API。上面的 JSX 转译后的对象大概是这样的:算法
{ _context: Object, _owner: null, key: null, props: { className: 'element', children: 'I'm element' }, ref: null, type: "div" } 复制代码
除了使用 JSX 语法,咱们还可使用 React.createElement() 和 React.cloneElement() 来构建 React 元素。设计模式
React 组件api
React 中有三种构建组件的方式。React.createClass()、ES6 class和无状态函数。数组
一、React.createClass()浏览器
var Greeting = React.createClass({ render: function() { return <h1>Hello, {this.props.name}</h1>; } }); 复制代码
二、ES6 classbash
class Greeting extends React.Component{ render: function() { return <h1>Hello, {this.props.name}</h1>; } }; 复制代码
三、无状态函数markdown
无状态函数是使用函数构建的无状态组件,无状态组件传入props和context两个参数,它没有state,除了render(),没有其它生命周期方法。
function Greeting (props) { return <h1>Hello, {props.name}</h1>; } 复制代码
四、PureComponent
除了为你提供了一个具备浅比较的shouldComponentUpdate方法,PureComponent和Component基本上彻底相同。
元素与组件的区别
组件是由元素构成的。元素数据结构是普通对象,而组件数据结构是类或纯函数。
是父组件用来获取子组件的dom元素的,为何有这个API,缘由以下
// 例若有一个子组件和父组件,代码以下 子组件为: class Child extends React.Component{ constructor(props){ super(props); } render(){ return <input /> } } // 父组件中,ref: class Father extends React.Component{ constructor(props){ super(props); this.myRef=React.createRef(); } componentDidMount(){ console.log(this.myRef.current); } render(){ return <Child ref={this.myRef}/> } } 复制代码
此时父组件的this.myRef.current的值是Child组件,也就是一个对象,若是用了React.forwardRef,也就是以下
// 子组件 const Child = React.forwardRef((props, ref) => ( <input ref={ref} /> )); // 父组件 class Father extends React.Component { constructor(props) { super(props); this.myRef = React.createRef(); } componentDidMount() { console.log(this.myRef.current); } render() { return <Child ref={this.myRef} /> } } 复制代码
此时父组件的this.myRef.current的值是input这个DOM元素
注:答案参考司徒正美大神的文章
class Input extends Component{ constructor(){ super(); this.state = {val:'100'} } handleChange = (e) =>{ //e是事件源 let val = e.target.value; this.setState({val}); }; render(){ return (<div> <input type="text" value={this.state.val} onChange={this.handleChange}/> {this.state.val} </div>) } } 复制代码
class Sum extends Component{ constructor(){ super(); this.state = {result:''} } //经过ref设置的属性 能够经过this.refs获取到对应的dom元素 handleChange = () =>{ let result = this.refs.a.value + this.b.value; this.setState({result}); }; render(){ return ( <div onChange={this.handleChange}> <input type="number" ref="a"/> {/*x表明的真实的dom,把元素挂载在了当前实例上*/} <input type="number" ref={(x)=>{ this.b = x; }}/> {this.state.result} </div> ) } } 复制代码
使用 react 常常会遇到几个组件须要共用状态数据的状况。这种状况下,咱们最好将这部分共享的状态提高至他们最近的父组件当中进行管理。咱们来看一下具体如何操做吧。
import React from 'react' class Child_1 extends React.Component{ constructor(props){ super(props) } render(){ return ( <div> <h1>{this.props.value+2}</h1> </div> ) } } class Child_2 extends React.Component{ constructor(props){ super(props) } render(){ return ( <div> <h1>{this.props.value+1}</h1> </div> ) } } class Three extends React.Component { constructor(props){ super(props) this.state = { txt:"牛逼" } this.handleChange = this.handleChange.bind(this) } handleChange(e){ this.setState({ txt:e.target.value }) } render(){ return ( <div> <input type="text" value={this.state.txt} onChange={this.handleChange}/> <p>{this.state.txt}</p> <Child_1 value={this.state.txt}/> <Child_2 value={this.state.txt}/> </div> ) } } export default Three 复制代码
高阶组件不是组件,是 加强函数,能够输入一个元组件,返回出一个新的加强组件
function proxyHoc(WrappedComponent) { return class extends React.Component { render() { const newProps = { count: 1 } return <WrappedComponent {...this.props} {...newProps} /> } } } 复制代码
const MyContainer = (WrappedComponent)=>{ return class extends WrappedComponent { render(){ return super.render(); } } } 复制代码
Context 经过组件树提供了一个传递数据的方法,从而避免了在每个层级手动的传递 props 属性。
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')); 复制代码
Portals 提供了一种很好的将子节点渲染到父组件之外的 DOM 节点的方式。
ReactDOM.createPortal(child, container)
复制代码
第一个参数(child)是任何可渲染的 React 子元素,例如一个元素,字符串或碎片。第二个参数(container)则是一个 DOM 元素。
部分 UI 中的 JavaScript 错误不该该破坏整个应用程序。 为了解决 React 用户的这个问题,React 16引入了一个 “错误边界(Error Boundaries)” 的新概念。
import React from 'react'; import ReactDOM from 'react-dom'; class ErrorBoundary extends React.Component{ constructor(props) { super(props); this.state={hasError:false}; } componentDidCatch(err,info) { this.setState({hasError: true}); } render() { if (this.state.hasError) { return <h1>Something Went Wrong</h1> } return this.props.children; } } class Page extends React.Component{ render() { return ( <ErrorBoundary> <Clock/> </ErrorBoundary> ) } } class Clock extends React.Component{ render() { return ( <div>hello{null.toString()}</div> ) } } ReactDOM.render(<Page/>,document.querySelector('#root')); 复制代码
增长dangerouslySetInnerHTML属性,而且传入对象的属性名叫_html
function Component(props){ return <div dangerouslySetInnerHTML={{_html:'<span>你好</span>'}}> </div> } 复制代码
举例说明
变化前数组的值是[1,2,3,4],key就是对应的下标:0,1,2,3
变化后数组的值是[4,3,2,1],key对应的下标也是:0,1,2,3
复制代码
变化前数组的值是[1,2,3,4],key就是对应的下标:id0,id1,id2,id3
变化后数组的值是[4,3,2,1],key对应的下标也是:id3,id2,id1,id0
复制代码