react学习笔记-基础知识

props

  1. 在函数式组件里面, 使用传参的形式拿到props
  2. 在es6 class语法里面, 使用this.props拿到 props
  3. props是只读属性
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

function App() {
  return (
    <div>
      <Welcome name="Sara" />
      <Welcome name="Cahal" />
      <Welcome name="Edite" />
    </div>
  );
}

ES6 class写法

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

生命周期

  1. componentDidMount 组件挂载完毕

  2. componentWillUnmount 组件即将卸载

state


  constructor(props) {
    super(props);
    this.state = {date: new Date()};  // 定义一个state
  }


  1. 注意事项:
this.state.comment = 'Hello';  // 此代码不会重新渲染组件:

|
| 正确使用方式
| --------------->

this.setState({comment: 'Hello'});
  1. 注意事项2

this.props为异步获取数据, this.state也可能是异步获取数据, 当props或state数据改变, 可能会导致数据不会更新

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

|
| 正确使用方式
| --------------->

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

|
| 或正确使用方式
| --------------->

this.setState(function(prevState, props) {
  return {
    counter: prevState.counter + props.increment
  };
});

事件绑定

  1. 基础例子:
<button onClick={activateLasers}>
  Activate Lasers
</button>
  1. 注意事项:
  • 不能 return false的方式 阻止默认行为 必须明确的使用 preventDefault
function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }
  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}

  1. 绑定this
    JSX 回调函数中的 this,类的方法默认是不会绑定 this 的, this 的值会是 undefined。

解决方法1: 在constructor 中显示的为 函数 使用 Bind方法绑定this

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};
    this.handleClick = this.handleClick.bind(this);  // 这里绑定了this
  }
  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }
  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}
ReactDOM.render(
  <Toggle />,
  document.getElementById('root')
);

解决方法2: 函数使用es6箭头函数的方式声明

  handleClick = () => {
    console.log('this is:', this);
  }

解决方法3:

<button onClick={(e) => this.handleClick(e)}>
        Click me
      </button>

解决方法4:

<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

条件渲染

1.在方法内部使用if/else

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}
ReactDOM.render(
  // Try changing to isLoggedIn={true}:
  <Greeting isLoggedIn={false} />,
  document.getElementById('root')
);
  1. 在render内部使用判断语句
render() {
    const isLoggedIn = this.state.isLoggedIn;
    let button = null;
    if (isLoggedIn) {
      button = <div>我是组件1</div;
    } else {
      button =<div>我是组件2</div;
    }
    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {button}
      </div>
    );
  }
}

  1. 使用与运算符 &&
function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h1>Hello!</h1>
      {unreadMessages.length > 0 &&
        <h2>
          You have {unreadMessages.length} unread messages.
        </h2>
      }
    </div>
  );
}
  1. 三目运算符
render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
    </div>
  );
}

|
|
| 或这样
------------->

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      {isLoggedIn ? (
        <LogoutButton onClick={this.handleLogoutClick} />
      ) : (
        <LoginButton onClick={this.handleLoginClick} />
      )}
    </div>
  );
}

  1. 阻止组件渲染
function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }

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

map渲染

循环的时候记得加key

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')
);

keys 与组件

  1. 被循环的根组件内添加key
  2. 数组元素中使用的key在其兄弟之间应该是独一无二的。然而,它们不需要是全局唯一的
  return (
    // 错啦!你不需要在这里指定key:
    <li key={value.toString()}>
      {value}
    </li>
  );
    const listItems = numbers.map((number) =>
      //错啦!元素的key应该在这里指定:
      <ListItem value={number} />
    );

|
|
| 正确使用
|-------》

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

JSX允许在大括号中嵌入任何表达式,

  return (
    <ul>
      {numbers.map((number) =>
        <ListItem key={number.toString()}
                  value={number} />
      )}
    </ul>
  );

受控组件

  1. input
  • 使用value={this.state.value}绑定数据, 然后通过change事件修改state.value数据
class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};
    this.handleChange = this.handleChange.bind(this);
  }

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

  render() {
    return (
          <input type="text" value={this.state.value} onChange={this.handleChange} />
    );
  }
}



  1. textarea

textarea标签的使用方式跟Input一样, 不同的是, 在react中, textarea会用value属性来代替

  1. select

Coconut选项最初由于selected属性是被选中的。在React中,并不使用之前的selected属性,而在根select标签上用value属性来表示选中项

<select value={this.state.value} onChange={this.handleChange}>
            <option value="grapefruit">Grapefruit</option>
            <option value="lime">Lime</option>
            <option value="coconut">Coconut</option>
            <option value="mango">Mango</option>
          </select>
  1. input file标签

由于该标签的 value 属性是只读的, 所以它是 React 中的一个非受控组件。

组件交互(状态提升)

//------------------------  父组件
class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
    this.state = {temperature: ''};
  }
    // 注册方法
  handleCelsiusChange(temperature) {
    this.setState({temperature});
  }
  render() {
    const celsius = this.state.temperature;
    return (
      <div>
        <TemperatureInput
        // 传递参数值给子组件
          temperature={celsius}
          // 将方法通过prop传递过去
          onTemperatureChange={this.handleCelsiusChange} />
      </div>
    );
  }
}


//------------------------  子组件

class TemperatureInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }
  // 触发父组件传递过来的参数的方法, 吧值传递回去
  handleChange(e) {
    this.props.onTemperatureChange(e.target.value);
  }
  render() {
    const temperature = this.props.temperature;
    return (
      <fieldset>
      // 接收到父组件传递过来的参数, 并赋值给自己
        <input value={temperature}
        // 注册自己的change事件
               onChange={this.handleChange} />
      </fieldset>
    );
  }
}

props.children 子代

通过props.children渲染组件内的内容

  1. 渲染内部所有内容
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>
  );
}

  1. 内部内容指定渲染位置
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 />
      } />
  );
}

jsx与react

  1. react组件与react调用
<MyButton color="blue" shadowSize={2}>
  Click Me
</MyButton>

|
| 转换
|----->

React.createElement(
  MyButton,
  {color: 'blue', shadowSize: 2},
  'Click Me' // 当使用自闭合标签(<div/>) 的时候, 里面是没有内容的,可以使用Null放在这里
)
  1. 点表示法
    也可以使用对象的形式作为组件
import React from 'react';
const MyComponents = {
  DatePicker: function DatePicker(props) {
    return <div>Imagine a {props.color} datepicker here.</div>;
  }
}
function BlueDatePicker() {
  return <MyComponents.DatePicker color="blue" />;
}

  1. 首字母大写
import React from 'react';
// 正确!组件名应该首字母大写:
function Hello(props) {
  // 正确!div 是有效的 HTML 标签:
  return <div>Hello {props.toWhat}</div>;
}
function HelloWorld() {
  // 正确!React 能够将大写开头的标签名认为是 React 组件。
  return <Hello toWhat="World" />;
}
  1. 组件变量


import React from 'react';
import { PhotoStory, VideoStory } from './stories';

const components = {
  photo: PhotoStory,
  video: VideoStory
};

function Story(props) {
  // 正确!JSX 标签名可以为大写开头的变量。
  const SpecificStory = components[props.storyType];
  return <SpecificStory story={props.story} />;
  //-------------------------------
  // 错误!JSX 标签名不能为一个表达式。
    return <components[props.storyType] story={props.story} />;
}

  1. 属性中的表达式

你可以传递任何 {} 包裹的 JavaScript 表达式作为一个属性值

<MyComponent foo={1 + 2 + 3 + 4} />

if 语句和 for 循环在 JavaScript 中不是表达式,因此它们不能直接在 JSX 中使用,但是你可以将它们放在周围的代码中。

function NumberDescriber(props) {
  let description;
  if (props.number % 2 == 0) {
    description = <strong>even</strong>;
  } else {
    description = <i>odd</i>;
  }
  return <div>{props.number} is an {description} number</div>;
}

  • 字符串常量
<MyComponent message="hello world" />
=========
<MyComponent message={'hello world'} />
  • 默认为 True
<MyTextBox autocomplete />
=======
<MyTextBox autocomplete={true} />
  • 扩展属性
function App2() {
  const props = {firstName: 'Ben', lastName: 'Hector'};
  return <Greeting {...props} />;
}
  • 渲染时, 布尔值, Null, undefined 被忽略, 下面的都等价
<div></div>

<div>{false}</div>

<div>{null}</div>

<div>{undefined}</div>

<div>{true}</div>

propTypes检测类型

  1. 限制类型
import PropTypes from 'prop-types';
class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}
Greeting.propTypes = {
  name: PropTypes.string
};

具体验证例子请打开该链接
https://react.docschina.org/docs/typechecking-with-proptypes.html

  1. 限制单个子代


import PropTypes from 'prop-types';

class MyComponent extends React.Component {
  render() {
    // This must be exactly one element or it will warn.
    const children = this.props.children;
    return (
      <div>
        {children}
      </div>
    );
  }
}

MyComponent.propTypes = {
  children: PropTypes.element.isRequired
};

  1. 属性默认值

// 为属性指定默认值:
Greeting.defaultProps = {
  name: 'Stranger'
};

refs

  • 你不能在函数式组件上使用 ref 属性
  • ref 的更新会发生在componentDidMount 或 componentDidUpdate 生命周期钩子之前
    使用 React.createRef() 创建 refs,通过 ref 属性来获得 React 元素
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}
  1. 通过this.myRef.current 拿到dom元素
class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    // 创建 ref 存储 textInput DOM 元素
    this.textInput = React.createRef();
    this.focusTextInput = this.focusTextInput.bind(this);
  }

  focusTextInput() {
    // 直接使用原生 API 使 text 输入框获得焦点
    // 注意:通过 "current" 取得 DOM 节点
    this.textInput.current.focus();
  }

  render() {
    // 告诉 React 我们想把 <input> ref 关联到构造器里创建的 `textInput` 上
    return (
      <div>
        <input
          type="text"
          ref={this.textInput} />

        <input
          type="button"
          value="Focus the text input"
          onClick={this.focusTextInput}
        />
      </div>
    );
  }
}
  1. 回调 Refs
class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.textInput = null;
    // 这里的回调 把当前元素赋值给this.textInput
    this.setTextInputRef = element => {
      this.textInput = element;
    };

    this.focusTextInput = () => {
      // 直接使用原生 API 使 text 输入框获得焦点
      if (this.textInput) this.textInput.focus();
    };
  }

  componentDidMount() {
    // 渲染后文本框自动获得焦点
    this.focusTextInput();
  }

  render() {
    // 使用 `ref` 的回调将 text 输入框的 DOM 节点存储到 React
    // 实例上(比如 this.textInput)
    return (
      <div>
        <input
          type="text"
          ref={this.setTextInputRef}
        />
        <input
          type="button"
          value="Focus the text input"
          onClick={this.focusTextInput}
        />
      </div>
    );
  }
}


非受控组件

  1. 基础用法
class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  handleSubmit(event) {
    alert('A name was submitted: ' + this.input.value);
    event.preventDefault();
  }
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          // 这里拿到DOM元素
          <input type="text" ref={(input) => this.input = input} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}
  1. 默认值 defaultValue

你希望 React 可以为其指定初始值,但不再控制后续更新。 你可以指定一个 defaultValue 属性而不是 value
同样,<input type="checkbox"> 和 <input type="radio"> 支持 defaultChecked,<select> 和 <textarea> 支持 defaultValue.

<input
          defaultValue="Bob"
          type="text"
          ref={(input) => this.input = input} />

Context

Context 可以用来跨子组件给更下级的组件传参

  1. 创建一个Context
  • Provider 作为传递组件的根组件
  • Consumer 作为Provider 下的接收参数的组件Consumer
const {Provider, Consumer} = React.createContext(defaultValue);
  • 接收一个 value 属性传递给 Provider 的后代 Consumers。一个 Provider 可以联系到多个 Consumers。
<Provider value={/* some value */}>
  • Consumer
<Consumer>
// 这里接收一个函数, 传递值为 Provider的value
  {value => /* render something based on the context value */}
</Consumer>

示例

export const themes = {
  light: {
    foreground: '#ffffff',
    background: '#222222',
  },
  dark: {
    foreground: '#000000',
    background: '#eeeeee',
  },
};

export const ThemeContext = React.createContext(
  themes.dark // 默认值
);


import {ThemeContext} from './theme-context';

function ThemedButton(props) {
  return (
  // 定义  Consumer
    <ThemeContext.Consumer>
      {theme => (
        <button
          {...props}
          style={{backgroundColor: theme.background}}
        />
      )}
    </ThemeContext.Consumer>
  );
}
export default ThemedButton;

import {ThemeContext, themes} from './theme-context';
import ThemedButton from './themed-button';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      theme: themes.light,
    };

    this.toggleTheme = () => {
      this.setState(state => ({
        theme:
          state.theme === themes.dark
            ? themes.light
            : themes.dark,
      }));
    };
  }

  render() {
    return (
      <Page>
      //  定义 Provider
        <ThemeContext.Provider value={this.state.theme}>
          <ThemedButton onClick={this.toggleTheme} />  // 点击切换Provider.value
        </ThemeContext.Provider>
      </Page>
    );
  }
}
ReactDOM.render(<App />, document.root);

Fragments 空的 JSX 标签:

  1. 作用: 当渲染td的时候, 需要一个根组件, 但却不能随便使用, 因此可以使用一个空标签代替;
class Columns extends React.Component {
  render() {
    return (
      <div>
        <td>Hello</td>
        <td>World</td>
      </div>
    );
  }
}

|
|
| 输出结果
|- -------->

<table>
  <tr>
    <div>  // 这里多了div
      <td>Hello</td>
      <td>World</td>
    </div>
  </tr>
</table>
  1. <React.Fragment> 与<>
 <React.Fragment> == <>
  1. Fragment的属性
  • key 是唯一可以传递给 Fragment 的属性
<React.Fragment key={item.id}></React.Fragment>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容

  • React简介 (1)简介 React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaSc...
    鱼鱼吃猫猫阅读 1,613评论 1 6
  • 最近看了一本关于学习方法论的书,强调了记笔记和坚持的重要性。这几天也刚好在学习React,所以我打算每天坚持一篇R...
    gaoer1938阅读 1,672评论 0 5
  • 本笔记基于React官方文档,当前React版本号为15.4.0。 1. 安装 1.1 尝试 开始之前可以先去co...
    Awey阅读 7,671评论 14 128
  • $ 前言   最近在考虑框架转型,鉴于作为一名JSer,要时时刻刻保持对新技术和流行技术的敏感性,而 React、...
    果汁凉茶丶阅读 21,994评论 5 32
  • 很难理解,像跑步这种极其枯燥、百无聊赖的活动,居然会成为一种极为时髦的高级运动,可情况它就是这样。 更难以想像的是...
    大米一一阅读 302评论 0 0