美文网首页
react入门指南

react入门指南

作者: zxhnext | 来源:发表于2019-05-15 12:14 被阅读0次

1. 组件

1.1. 函数式

定义一个组件最简单的方式是使用JavaScript函数:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

该函数是一个有效的React组件,它接收一个单一的“props”对象并返回了一个React元素。我们之所以称这种类型的组件为函数定义组件,是因为从字面上来看,它就是一个JavaScript函数。

1.2. es6形式

也可以使用 ES6 class来定义一个组件:

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

1.3. props

当React遇到的元素是用户自定义的组件,它会将JSX属性作为单个对象传递给该组件,这个对象称之为“props”。
例如,这段代码会在页面上渲染出”Hello,Sara”:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

const element = <Welcome name="Sara" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);

1.4. 高阶组件

https://react.docschina.org/docs/higher-order-components.html
高阶组件就是一个函数,它接收一个组件,然后返回一个组件,如果我们需要给一些组件加一些特定的参数活方法, 则可以用到高阶组件,来看一个例子:

import React from 'react'
import { AppContext } from './AppContext'

const withContext = (Component) => {
  return (props) => (
    <AppContext.Consumer>
      {({ state, actions }) => {
        return <Component {...props} data={state} actions={actions} />
      }}
    </AppContext.Consumer>
  )
}
export default withContext

create.js

export default withContext(CreatePage)

1.5 展示型组件

image.png

来看一个例子:

// 父组件
modifyItem = (item) => {
    this.props.history.push(`/edit/${item.id}`)
}
<PriceList 
    items={itemsWithCategory}
    onModifyItem={this.modifyItem}
/>

// 子组件
const PriceList = ({ items, onModifyItem }) => {
  return (
    <ul className="list-group list-group-flush">
      {
        items.map((item) => (
          <li className="list-group-item d-flex 
            justify-content-between align-items-center"
            key={item.id}
          >
              <a className="col-1"
                  role="button"
                  onClick={(event) => {event.preventDefault(); onModifyItem(item)}}
                >
          </li>
        ))
      }
    </ul>
  )
}

1.6 容器组件

image.png

2. 生命周期

这是官网的生命周期图例:


image.png

componentWillMount()
组件初始化时只调用,以后组件更新不调用,整个生命周期只调用一次,此时可以修改state。

render()
react最重要的步骤,创建虚拟dom,进行diff算法,更新dom树都在此进行。此时就不能更改state了。

componentDidMount()
组件渲染之后调用,只调用一次。

componentWillReceiveProps(nextProps)
组件初始化时不调用,组件接受新的props时调用。

shouldComponentUpdate(nextProps, nextState)
react性能优化非常重要的一环。组件接受新的state或者props时调用,我们可以设置在此对比前后两个props和state是否相同,如果相同则返回false阻止更新,因为相同的属性状态一定会生成相同的dom树,这样就不需要创造新的dom树和旧的dom树进行diff算法对比,节省大量性能,尤其是在dom结构复杂的时候

componentWillUpdata(nextProps, nextState)
组件初始化时不调用,只有在组件将要更新时才调用,此时可以修改state

render()
组件渲染

componentDidUpdate()
组件初始化时不调用,组件更新完成后调用,此时可以获取dom节点。

componentWillUnmount()
组件将要卸载时调用,一些事件监听和定时器需要在此时清除。

3. state

状态的更新过程是异步的,React 可以将多个setState() 调用合并成一个调用来提高性能。

因为 this.props 和 this.state 可能是异步更新的,所以不应该依靠它们的值来计算下一个状态。

例如,以下代码的结果可能是错误的:

this.setState({
  counter: this.state.counter + this.props.increment,
});

要修复它,请使用第二种形式的 setState() 来接受一个函数而不是一个对象。 该函数将接收先前的状态作为第一个参数,将此次更新被应用时的props做为第二个参数:

this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

4. 条件渲染

4.1 元素变量

if (isLoggedIn) {
      button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
      button = <LoginButton onClick={this.handleLoginClick} />;
}

4.2 与运算符

{unreadMessages.length > 0 &&
        <h2>
          You have {unreadMessages.length} unread messages.
        </h2>
}

4.3 三目运算符

{isLoggedIn ? (
        <LogoutButton onClick={this.handleLogoutClick} />
      ) : (
        <LoginButton onClick={this.handleLoginClick} />
)}

4.4 阻止组件渲染
在极少数情况下,你可能希望隐藏组件,即使它被其他组件渲染。让 render 方法返回 null 而不是它的渲染结果即可实现。

function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }

  return (
    <div className="warning">
      Warning!
    </div>
  );
}

5. 列表循环

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);
// 或
function NumberList(props) {
  const numbers = props.numbers;
  return (
    <ul>
      {numbers.map((number) =>
        <ListItem key={number.toString()}
                  value={number} />

      )}
    </ul>
  );
}

Keys可以在DOM中的某些元素被增加或删除的时候帮助React识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。

如果你提取出一个ListItem组件,你应该把key保存在数组中的这个<ListItem />元素上,而不是放在ListItem组件中的<li>元素上。

function ListItem(props) {
  // 对啦!这里不需要指定key:
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    // 又对啦!key应该在数组的上下文中被指定
    <ListItem key={number.toString()}
              value={number} />

  );
  return (
    <ul>
      {listItems}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

6. 组合继承

6.1 包含关系
一些组件不能提前知道它们的子组件是什么。这对于 Sidebar 或 Dialog 这类通用容器尤其常见。

我们建议这些组件使用 children 属性将子元素直接传递到输出。

function FancyBorder(props) {
  return (
    <div className={'FancyBorder FancyBorder-' + props.color}>
      {props.children}
    </div>
  );
}

function WelcomeDialog() {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        Welcome
      </h1>
      <p className="Dialog-message">
        Thank you for visiting our spacecraft!
      </p>
    </FancyBorder>
  );
}

有时你可能需要在组件中有多个入口,这种情况下你可以使用自己约定的属性而不是 children:

function SplitPane(props) {
  return (
    <div className="SplitPane">
      <div className="SplitPane-left">
        {props.left}
      </div>
      <div className="SplitPane-right">
        {props.right}
      </div>
    </div>
  );
}

function App() {
  return (
    <SplitPane
      left={
        <Contacts />
      }
      right={
        <Chat />
      } />
  );
}

6.2 特殊实例

function Dialog(props) {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        {props.title}
      </h1>
      <p className="Dialog-message">
        {props.message}
      </p>
    </FancyBorder>
  );
}

function WelcomeDialog() {
  return (
    <Dialog
      title="Welcome"
      message="Thank you for visiting our spacecraft!" />

  );
}

function Dialog(props) {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        {props.title}
      </h1>
      <p className="Dialog-message">
        {props.message}
      </p>
      {props.children}
    </FancyBorder>
  );
}

class SignUpDialog extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.handleSignUp = this.handleSignUp.bind(this);
    this.state = {login: ''};
  }

  render() {
    return (
      <Dialog title="Mars Exploration Program"
              message="How should we refer to you?">
        <input value={this.state.login}
               onChange={this.handleChange} />

        <button onClick={this.handleSignUp}>
          Sign Me Up!
        </button>
      </Dialog>
    );
  }

  handleChange(e) {
    this.setState({login: e.target.value});
  }

  handleSignUp() {
    alert(`Welcome aboard, ${this.state.login}!`);
  }
}

7. 实用技巧

可以覆盖展开后的title

let item = {
  "title": "标题",
  "content": "内容"
}
return {...item, title: "更新后的标题"}

将上一步数据返回后可以实现链式调用

items.filter(item => item.category.type === type).forEach((item) => {
    if (categoryMap[item.cid]) {
      categoryMap[item.cid].value += (item.price * 1)
      categoryMap[item.cid].items = [...categoryMap[item.cid].items, item.id]
    } else {
      categoryMap[item.cid] = {
        category: item.category,
        value: item.price * 1,
        items: [item.id]
      }
    }
})

函数动态传参,[]将参数变为变量

handleOpen = (type)=>{
    this.setState({
        [type]:true
    })
}

模拟数据:json-server

fetch缺点:

concurrently 可以运行多个npm命令

react中package.json中也可以开启代理:

"proxy": "http://localhost:3004"

8. 动画与公共样式

8.1 react-transition-group
Transiton是更底层的,CSSTransition实现不了的,可以用Transiton,TransitionGroup可以实现多个dom元素动画
使用方法:

import { CSSTransition } from 'react-transition-group'
<CSSTransition
    in={focused}
    timeout={200}
    classNames="slide"
>
    <div></div>
</CSSTransition>

8.2 styled-components
如果我们想把css以js形式来写,可以使用styled-components,首先我们可以定义全局样式

// style.js
import { createGlobalStyle } from 'styled-components';
export const GlobalStyle = createGlobalStyle`
  body{}
`
// app.js
import { GlobalStyle } from './style';
import { IconfontStyle } from './statics/iconfont/iconfont.js'; // 引入字体包
class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <GlobalStyle />
        <IconfontStyle />
      </Provider>
    )
  }
}

// 组件样式引入
// style.js
import styled from 'styled-components';
export const HeaderWrapper = styled.div`
    position: relative;
    height: 56px;
    border-bottom: 1px solid #f0f0f0;
    z-index: 1;
`;
// index.js
import {
    HeaderWrapper
} from './style';

<HeaderWrapper></HeaderWrapper>

8.3 沙箱css
首先我们需要配置webpack
在config目录下的webpack.config.js中,开启模块化(配置stylus,less也在这里配置)
react中配置less: https://www.jianshu.com/p/dbc8e0e80de5

{
      test: cssModuleRegex,
      use: getStyleLoaders({
          importLoaders: 1,
           sourceMap: isEnvProduction
           ? shouldUseSourceMap
           : isEnvDevelopment,
          modules: true, // 开启模块化
          getLocalIdent: getCSSModuleLocalIdent,
     })
}

用法:

import styles from './index.module.less'
<div className={styles.detail}>
 
</div>
注意less文件要带.module.less的后缀

8.4 字体图标
推荐一个字体图标库:
[https://ionicons.com/](https://ionicons.com/)
复制.eot,.svg,.ttf,.woff文件包

9. sublime常用插件

image image

相关文章

网友评论

      本文标题:react入门指南

      本文链接:https://www.haomeiwen.com/subject/wpasoqtx.html