{"action":"opened","issue":{"url":"https://api.github.com/repos/kaisa911/studyNotes/issues/2","repository_url":"https://api.github.com/repos/kaisa911/studyNotes","labels_url":"https://api.github.com/repos/kaisa911/studyNotes/issues/2/labels{/name}","comments_url":"https://api.github.com/repos/kaisa911/studyNotes/issues/2/comments","events_url":"https://api.github.com/repos/kaisa911/studyNotes/issues/2/events","html_url":"https://github.com/kaisa911/studyNotes/issues/2","id":320172625,"number":2,"title":"react v.16的新特性学习","user":{"login":"kaisa911","id":20339105,"avatar_url":"https://avatars2.githubusercontent.com/u/20339105?v=4","gravatar_id":"","url":"https://api.github.com/users/kaisa911","html_url":"https://github.com/kaisa911","followers_url":"https://api.github.com/users/kaisa911/followers","following_url":"https://api.github.com/users/kaisa911/following{/other_user}","gists_url":"https://api.github.com/users/kaisa911/gists{/gist_id}","starred_url":"https://api.github.com/users/kaisa911/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kaisa911/subscriptions","organizations_url":"https://api.github.com/users/kaisa911/orgs","repos_url":"https://api.github.com/users/kaisa911/repos","events_url":"https://api.github.com/users/kaisa911/events{/privacy}","received_events_url":"https://api.github.com/users/kaisa911/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2018-05-04T07:08:31Z","updated_at":"2018-05-04T07:08:31Z","closed_at":null,"author_association":"OWNER","body":"1、Fragment\r\n\r\n新版本的render可以返回数组、字符串、react组件、数字、boolean值\r\nv15.x必须要一个标签来包裹<br>\r\nBefore v16\r\n\r\n```\r\nreturn (\r\n        <div>\r\n            <label htmlFor=\"name\">名字：</label>\r\n            <input id=\"name\" type=\"text\" placeholder=\"请输入名字\"/>\r\n            <button>搜索</button>\r\n        </div>\r\n    );\r\n```\r\n\r\nWhen v16.0.0\r\n\r\n```\r\nreturn (\r\n    [\r\n        <label htmlFor=\"name\">名字：</label>,\r\n        <input id=\"name\" type=\"text\" placeholder=\"请输入名字\"/>,\r\n        <button>搜索</button>\r\n    ]\r\n);\r\n```\r\n\r\nNow v16.2.0\r\n\r\n```\r\nreturn (\r\n    <React.Fragment>\r\n       <label htmlFor=\"name\">名字：</label>\r\n       <input id=\"name\" type=\"text\" placeholder=\"请输入名字\"/>\r\n       <button>搜索</button>\r\n    </React.Fragment>\r\n);\r\n```\r\n\r\n片段(fragments) 可以让你将子元素列表添加到一个分组中，并且不会在DOM中增加额外节点。key 是唯一可以传递给 Fragment 的属性\r\n\r\n```\r\nreturn (\r\n    <dl>\r\n      {props.items.map(item => (\r\n        // 没有`key`，将会触发一个key警告\r\n        <React.Fragment key={item.id}>\r\n          <dt>{item.term}</dt>\r\n          <dd>{item.description}</dd>\r\n        </React.Fragment>\r\n      ))}\r\n    </dl>\r\n  );\r\n```\r\n\r\n简明写法<></>，但是还没有被更多的工具支持，它不支持 键(keys) 或 属性(attributes)。\r\n\r\nFurther\r\n\r\nbabel v7.0.0+ , babel-plugin-transform-react-jsx-source or babel-preset-react\r\n\r\n```\r\nreturn (\r\n    <>\r\n       <label htmlFor=\"name\">名字：</label>\r\n       <input id=\"name\" type=\"text\" placeholder=\"请输入名字\"/>\r\n       <button>搜索</button>\r\n    </>\r\n);\r\n```\r\n\r\nDOM Fragment\r\n\r\n```\r\nconst select = document.getElementById('select')\r\nconst values = [1, 2, 3]\r\nconst fragment = document.createDocumentFragment()\r\nvalues.map(item => {\r\n    const option = document.createElement('option')\r\n    option.value = item\r\n    option.innerHTML = `小明${item}号`\r\n    fragment.appendChild(option)\r\n})\r\nselect.appendChild(fragment)\r\n```\r\n\r\n2、Portals\r\n\r\nPortals是reactjs16提供的官方解决方案，使得组件可以脱离父组件层级挂载在DOM树的任何位置。\r\n普通情况下，组件的render函数返回的元素会被挂载在它的父级组件上。\r\n然而，有些元素需要被挂载在更高层级的位置。最典型的应用场景：当父组件具有overflow: hidden或者z-index的样式设置时，组件有可能被其他元素遮挡，就可以考虑使用Portal使组件的挂载脱离父组件。\r\n组件的挂载点虽然可以脱离父组件，但组件的事件通过冒泡机制仍可以传给父组件。\r\n\r\n```\r\n<body>\r\n    <div id=\"bd\"></div>\r\n    <div id=\"modal\"></div>\r\n</body>\r\n```\r\n\r\n```\r\nrender(\r\n  <App>\r\n    <SearchBox>\r\n      <Modal>\r\n        <div>模态框</div>\r\n      </Modal>\r\n    </SearchBox>\r\n  </App>,\r\n  document.getElementById('bd'),\r\n  () => {\r\n  console.log(arguments)\r\n})\r\n```\r\n\r\ncl\r\n\r\n```\r\nass App extends Component{\r\n  constructor(options) {\r\n    super(options)\r\n    this.handleClick = this.handleClick.bind(this)\r\n  }\r\n  handleClick() {\r\n    alert('react component tree propagation!')\r\n  }\r\n  render() {\r\n    return <div className=\"app\" onClick={this.handleClick}>\r\n      {this.props.children}\r\n    </div>\r\n  }\r\n}\r\n```\r\n\r\n```\r\nclass Modal extends Component {\r\n    constructor(options) {\r\n      super(options)\r\n    }\r\n    render() {\r\n      return createPortal(this.props.children, document.getElementById('modal'))\r\n    }\r\n  }\r\n```\r\n\r\n```\r\n<div id=\"bd\">\r\n    <div class=\"app\">\r\n        <label for=\"name\">名字：</label>\r\n        <input type=\"text\" id=\"name\" placeholder=\"请输入名字\">\r\n        <button>搜索</button>\r\n    </div>\r\n</div>\r\n<div id=\"modal\">\r\n    <div>模态框</div>\r\n</div>\r\n```\r\n\r\n```\r\n<App>\r\n    <div className=\"app\" onClick=bound handleClick()>\r\n        <SearchBox>\r\n            <labelhtmlFor=\"name\">名字：</label>\r\n            <inputid=\"name\"type=\"text\"placeholder=\"请输入名字\"></input>\r\n            <button>搜索</button>\r\n            <Modal>\r\n                <ReactPortal target=HTMLDivElement{…}>\r\n                    <div>模态框</div>\r\n                </ReactPortal>\r\n            </Modal>\r\n        </SearchBox>\r\n    </div>\r\n</App>\r\n```\r\n\r\nBefore portals\r\n\r\n```\r\nReactDom.render(reactChild, container, callback)\r\n\r\nReactDom.unmountComponentAtNode(container)\r\n\r\n\r\nReactDom.unstable_renderSubtreeIntoContainer(\r\n    context,\r\n    reactChild,\r\n    domNode,\r\n    callback\r\n)\r\n\r\nReactDom.unmountComponentAtNode(container)\r\n\r\n\r\nrender: ReactMount._renderSubtreeIntoContainer(null, reactChild, container, callback )\r\n\r\nunstable_renderSubtreeIntoContainer: ReactMount._renderSubtreeIntoContainer(context, reactChild, container, callback)\r\n```\r\n\r\n3、Error Boundaries\r\n\r\n之前react在渲染过程中或者是生命周期内出现了致命的错误，react会从根组件上把所有的组件都卸载下来，以防止展现错误的数据，但这不是最好的用户体验。React 16修复了这一点，引入了Error Boundary的概念，中文译为“错误边界”，当某个组件发生错误时，我们可以通过Error Boundary捕获到错误并对错误做优雅处理。（注：它并不能捕获runtime所有的错误，比如组件回调事件里的错误，可以把它想象成传统的try-catch语句）\r\n\r\n```\r\nclass ErrorBoundary extends React.Component {\r\n  constructor(props) {\r\n    super(props);\r\n    this.state = { hasError: false };\r\n  }\r\n// 新增了componentDidCatch这个生命周期函数，它可以捕获自身及子树上的错误并对错误做优雅处理，包括上报错误日志、展示出错提示，而不是卸载整个组件树。\r\n  componentDidCatch(error, info) {\r\n    // 错误代理组件的展示与否\r\n    this.setState({ hasError: true });\r\n    // 在这里我们可以对错误进行记录\r\n    logErrorToMyService(error, info);\r\n  }\r\n\r\n  render() {\r\n    if (this.state.hasError) {\r\n      // 在这里我们可以书写自己想要展示的ui组件\r\n      return <h1>Something went wrong.</h1>;\r\n    }\r\n    return this.props.children;\r\n  }\r\n}\r\n```\r\n\r\n上面的组件是当页面中有错误时我们想要展示的效果，具体用法如下:\r\n\r\n```\r\nrender(){\r\n  return (\r\n    <div>\r\n      <ErrorBoundary>    // 外层组件我们定义的错误组件\r\n        <Profile user={this.state.user} />     // 内层组件是我们将要监视的自定义组件\r\n      </ErrorBoundary>\r\n      <button onClick={this.onClick}>Update</button>\r\n    </div>\r\n  )\r\n}\r\n```\r\n\r\n这个组件能够不仅仅能够监听到本组件的错误，连同它下面的子组件的错误也可以监听到\r\n\r\n##不能捕获的错误\r\n\r\n - 事件处理 \r\n - 异步回调 \r\n - 服务端渲染 \r\n - error boundary组件自身抛出的错误（只能由父级捕获）\r\n##**react遇到未捕获的错误会怎么办**\r\n对 React16 来说，一个未捕获的错误会导致整个应用不能被挂载\r\n\r\n4、setState传入null时不会再触发更新\r\n\r\n之前的setState不管传入什么只要调用了这么方法就会渲染\r\n\r\n```\r\nselectCity(e){\r\n  const newValue = e.target.value;\r\n  this.setState((state)=>{\r\n    if(state.city===newValue){\r\n      return null;\r\n    }\r\n    return {city:newValue}\r\n  })\r\n)\r\n```\r\n\r\n5、v16.0支持自定义的dom属性\r\n\r\n之前的版本对于自定义属性react会在属性前加上data-**来进行处理，现在对于部分属性去除了这种写法，拥抱了原生dom，这样可以减少react的代码，提升了性能\r\n\r\n6、其他\r\n\r\n更好的服务器端渲染：React 16的SSR被完全重写，新的实现非常快，接近3倍性能于React 15，现在提供一种流模式streaming，可以更快地把渲染的字节发送到客户端。\r\n\r\nreact v16采用了最新的技术“Fiber.”\r\n\r\nReact Server Side Rendering 解决 SPA 应用的 SEO 问题"}}
{"actor":{"display_login":"kaisa911"}}