美文网首页
React的学习

React的学习

作者: 赵一矛 | 来源:发表于2018-08-30 14:43 被阅读0次

MVC是模型(model)-视图(view)-控制器(contraller)
React.js是一个帮助构建页面UI的库,React的组件就相当于MVC里面的view。React帮助我们将界面分成各个独立的小块,每一个块就是组件,这些组件之间可以组合,嵌套,就成了我们的页面。
React.js不是一个框架,它只是一个库,它只提供UI(view)层面的解决方案。在实际项目中,需要结合其它的库,如Redux、React-router来协助提供完整的解决方法。
一、HTML模版

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">

</script>
</body>
</html>

上面的模版中type="text/babel"
这是因为 React 独有的 JSX 语法,跟 JavaScript 不兼容。凡是使用 JSX 的地方,都要加上 type="text/babel" 。
上面代码一共使用了三个库:

  • react.js
    是React的核心库
  • react-dom.js
    是提供与DOM相关的功能
  • Browser.js
    是将JSX语法转为JavaScript语法,这一步很消耗时间,实际上线的时候,应该放到服务器。

ReactDOM.render()

ReactDOM.render是React的最基本的方法,用于将模版转为HTML语言,并插入到对应的DOM节点。

 ReactDOM.render(
            <h1>Hello, world!</h1>,
            document.getElementById('example')
        );

React元素渲染

元素是构成React应用的最小单位,它用于描述屏幕上输出的内容。
ReactDOM.render()将其内容渲染在页面上。

 <div id="example"></div>
  <script type="text/babel">
      const element=<h1>Hello,world!</h1>;
      ReactDOM.render(
        element,
      document.getElementById('example')
      ); 
      </script>
image.png
更新元素渲染

React元素都是不可变的,当元素被创建后,就无法改变其内容或者属性的。
目前更新界面的唯一方法是创建一个新的元素,然后将它传入ReactDOM.render()方法。

<div id="example"></div>
  <script type="text/babel">
     function tick(){
       const element=(
         <div>
         <h1>Hello, world!</h1>
         <h2>现在是{new Date().toLocaleTimeString()}.</h2>
         </div>
       );
       ReactDOM.render(
         element,
         document.getElementById('example')
       );
     }

     setInterval(tick,1000);
      </script>
image.png
setInterval()方法,每秒钟调用一次ReactDOM.render()。
我们可以将要展示的部分封装起来
 function Clock(props){
      return (
        <div>
        <h1>Hello world!</h1>
        <h2>现在是{props.date.toLocaleTimeString()}.</h2>
        </div>
      )
    }

    function tick(){
      ReactDOM.render(
        <Clock date={new Date()} />,
        document.getElementById("example")
      )
    }

    setInterval(tick,1000);
      </script>

除了函数外我们还可以创建一个React.Component的ES6类,该类封装了要展示的元素,需要注意的是在render()方面中,需要使用this.props替换props.

class Clock extends React.Component{
      render(){
        return (
          <div>
          <h1>Hello, world!</h1>
          <h2>现在是{this.props.date.toLocaleTimeString()}</h2>
          </div>
        )
      }
    }
    function tick() {
      ReactDOM.render(
        <Clock date={new Date()} />,
        document.getElementById('example')
      )
    }
    setInterval(tick,1000);

JSX语法

ReactDOM.render(
  <div>
  {
    names.map(function (name) {
      return <div>Hello, {name}!</div>
    })
  }
  </div>,
 document.getElementById('example')
);

上面代码体现了 JSX 的基本语法规则:遇到 HTML 标签(以 < 开头),就用 HTML 规则解析;遇到代码块(以 { 开头),就用 JavaScript 规则解析。

  • JSX中不能使用if-else
ReactDOM.render(
    <div>
      <h1>{i == 1 ? 'True!' : 'False'}</h1>
    </div>
    ,
    document.getElementById('example')
);

React推荐使用内联样式,我们可以使用camelCase语法来设置内联样式,React会在指定元素数字后面自动添加px。

let myStyle={
    fontSize:100,
    color:'#FF0000'
};
ReactDOM.render(
    <div>
        <h1 style={myStyle}>Hello World!</h1>
    </div>,
    document.getElementById('example')
  );
注释

注释需要写在花括号中。

 {/*注释...*/}
数组

JSX允许在模版中插入数组,数组会自动展开所有成员。

let arr=[
    <h1>Hello</h1>,
    <h2>world</h2>
];
ReactDOM.render(
    <div>
        {arr}
    </div>,
    document.getElementById('example')
  );
独立文件

我们可以把React JSX代码可以放在一个独立的文件,在HTML中引入该JS。

React组件

1、定义一个组件

  • 可以使用函数定义一个组件
function HelloMessage(props) {
    return <h1>Hello World!</h1>;
}
  • 可以使用ES6 class来定义一个组件
class Welcome extends React.Component {
  render() {
    return <h1>Hello World!</h1>;
  }
}

2、为用户自定义的组件
const element=<Welcome />;
注意:原生HTML元素名以小写字母开头,而自定义的React类名以大写字母开头,比如HelloMessage不能写成helloMessage。除此之外还需要注意组件类只能包含一个顶层标签,否则也能报错。

  • 如果需要传递参数


    image.png

    注意:在添加属性时,class属性需要写成className,for属性需要写成htmlFor,这是因为class和for是js的保留字。

复合组件

可以创建多个组件来合成一个组件,即把组件的不同功能点进行分离。

function Name(props){
    return <h1>网站名称:{props.name}</h1>;
}
function URL(props){
    return  <h1>网站地址:{props.url}</h1>;
}
function NickName(props){
    return <h1>网站小名:{props.nickname}</h1>;
}
function App(){
    return (
        <div>
            <Name  name="百度"/>
            <URL url="http://www.baidu.com"/>
            <NickName nickname="百"/>
        </div>
    );
}
ReactDOM.render(
    <App />,
    document.getElementById('example')
);

App组件使用了Name,Url,NickName组件来输出对应的信息。

React State(状态)

React把组件看成是一个状态机。通过与用户的交互,实现不同状态,然后渲染UI,让用户界面和数据保持一致。
React中,只需要更新组件的state,然后根据新的state重新渲染用户界面(不需要操作DOM)
示例:在render()方法中使用this.state来修改当前时间。

class Clock extends React.Component{
    constructor(props){
        super(props);
        this.state={date:new Date()}
    }
    componentDidMount(){
        this.timeId=setInterval(
            ()=>this.tick(),
            1000
        );
    }
    componentWillUnmount(){
        clearInterval(this.timeId);
    }
    tick(){
        this.setState({
            date:new Date()
        });
    }
    render(){
        return(
            <div>
                <h1>Hello world!</h1>
                <h2>现在是{this.state.date.toLocaleTimeString()}</h2>
            </div>
        )
    }
}


ReactDOM.render(
    <Clock />,
    document.getElementById('example')
)

在具有许多组件的应用程序中国,在销毁时释放组件所占用的资源非常重要。
每当Clock组件第一次加载到DOM中的时候,我们都想生成定时器,这在React中被称为挂载。
同样,每当Clock生成的这个DOM被移除的时候,我们也会想要清除定时器,这在React中被称为卸载,我们可以在组件类上声明特殊的方法,当组件挂载或卸载时,来运行一些代码,如代码中的componentDidMount() ,componentWillUnmount()。
componentDidMount() ,componentWillUnmount()的方法被称作生命周期钩子。
在组件输出到 DOM 后会执行 componentDidMount() 钩子,我们就可以在这个钩子上设置一个定时器。

this.timerID 为计算器的 ID,我们可以在 componentWillUnmount() 钩子中卸载计算器。

React Props

state和props主要的区别在于props是不可变的,而state可以根据与用户交互来改变,这就是为什么有些容器组件需要定义state来更新和修改数据,而自组建只能通过props来传递数据。

Props示例

function HelloMessage(props){
    return <h1>Hello {props.name}!</h1>
}

const element=<HelloMessage name='Runoob'/>;

ReactDOM.render(
    element,
    document.getElementById('example')
)
image.png

上面代码中的name属性通过this.props.name来获取。
可以通过组件类的defaultProps属性为props设置默认值。

function HelloMessage(props){
    return <h1>Hello {props.name}!</h1>
}
HelloMessage.defaultProps={
    name:'Tom'
}

const element=<HelloMessage />;

ReactDOM.render(
    element,
    document.getElementById('example')
)

State和Props

我们可以在父组件中设置state,并通过在子组件上使用props将其传递到子组件上。在render函数中,我们设置name和site来获取父组件传递过来的数据。

class WebSite extends React.Component{
    constructor(){
        super();
        this.state={
            name:"百度",
            site:"http://www.baidu.com"
        }
    }
    render(){
        return(
            <div>
              <Name name={this.state.name} />
            <Link site={this.state.site} />
            </div>
        )
    }
}


class Name extends React.Component{
    render(){
        return(
            <h1>{this.props.name}</h1>
        )
    }
}

class Link extends React.Component{
    render(){
        return(
           <a href={this.props.site}>{this.props.site}</a>
        )
    }
}

ReactDOM.render(
    <WebSite />,
    document.getElementById('example')
)

Props验证

Props验证使用propTypes,它可以保证我们的应用组件被真确使用。
以下示例创建一个myTitle组件,属性title是必须的且是字符串,非字符串类型会自动转换为字符串。

var title="菜鸟教程";
class Mytitle extends React.Component{
    render(){
        return(
            <h1>Hello,{this.props.title}</h1>
        )
    }
}

Mytitle.propTypes = {
    title: PropTypes.string  
}

ReactDOM.render(
    <Mytitle title={title}/>,
    document.getElementById('example')
)

React事件处理

React元素的事件处理和DOM元素相似,但是有一点语法上的不同。

  • React事件绑定属性的命名采用驼峰式写法,而不是小写。
  • 如果采用JSX的语法你需要传入一个函数作为事件处理函数,而不是一个字符串。
    HTML 通常写法是:
<button onclick="activateLasers()">
  激活按钮
</button>

React 中写法为:

<button onClick={activateLasers}>
  激活按钮
</button>

示例

class Toggle extends React.Component {
    constructor(props) {
      super(props);
      this.state = {isToggleOn: true};
   
      // 这边绑定是必要的,这样 `this` 才能在回调函数中使用
      this.handleClick = this.handleClick.bind(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('example')
  );

React条件渲染

在React中,可以创建不同的组件来封装需要的行为,然后还可以根据应用的状态变化只渲染其中的一部分。
React中的条件渲染和JavaScript中的一致,使用JavaScript操作符if或者条件运算符来创建表示当前状态的元素,然后让React根据他们来更新UI。
两个组件:

function  UserGreeting(props){
    return <h1>欢迎回来</h1>
}
function GuestGreeting(props){
    return <h1>请先注册。</h1>
}

创建一个Greeting组件,根据用户是否登陆来显示其中之一。

function  UserGreeting(props){
    return <h1>欢迎回来</h1>
}

function GuestGreeting(props){
    return <h1>请先注册。</h1>
}

function Greeting(props){
    const isLoggedIn=props.isLoggedIn;
    if(isLoggedIn){
        return <UserGreeting/>
    }
    return <GuestGreeting/>
}

ReactDOM.render(
    <Greeting isLoggedIn={true}/>,
    document.getElementById('example')
)
元素变量

可以使用变量来存储元素,它可以帮助我们有条件的渲染组件的一部分,而输出的其他部分不会改变。
创造一个名为LoginControl的有状态的组件。
它会根据当前的状态来渲染<LoginButton/>或<LogoutButton/>,它也将渲染前面的例子中的<Greeting/>.

function  UserGreeting(props){
    return <h1>欢迎回来</h1>
}

function GuestGreeting(props){
    return <h1>请先注册。</h1>
}

function Greeting(props){
    const isLoggedIn=props.isLoggedIn;
    if(isLoggedIn){
        return <UserGreeting/>
    }
    return <GuestGreeting/>
}

function LoginButton(props){
    return (
        <button onClick={props.onClick}>登陆</button>
    )
}
function LogoutButton(props) {
    return (
      <button onClick={props.onClick}>
        退出
      </button>
    );
}
class LoginControl extends React.Component{
    constructor(props){
        super(props);
        this.handleLoginClick=this.handleLoginClick.bind(this);
        this.handleLogoutClick=this.handleLogoutClick.bind(this);
        this.state={isLoggedIn:false};
    }

    handleLoginClick(){
        this.setState({
            isLoggedIn:true
        })
    }
    handleLogoutClick(){
        this.setState({
            isLoggedIn:false
        });
    }

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

        return(
            <div>
                <Greeting isLoggedIn={isLoggedIn}/>
                {button}
            </div>
        )
    }

}

ReactDOM.render(
    <LoginControl/>,
    document.getElementById('example')
)

与运算符&&

可以通过用花括号包裹代码在JSX中嵌入任何表达式,也包括js的逻辑与.

function Mailbox(props){
    const unreadMessage=props.unreadMessage;
    return (
        <div>
            <h1>Hello!</h1>
            {unreadMessage.length>0 && <h2>您有{unreadMessage.length}条未读信息。</h2>}
            </div>
    )
}

const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
    <Mailbox unreadMessage={messages}/>,
    document.getElementById('example')
)

在js中,true&&expression,而false && expression总是返回false.因此,如果条件是true,&&右侧的元素就会被渲染,如果是false,React会忽略并跳过它。

阻止组件渲染

在极少数的情况下,可能希望隐藏组件,让render方法返回null而不是它的渲染解决既可以实现。

function WarningBanner(props) {
    if (!props.warn) {
      return null;
    }
   
    return (
      <div className="warning">
        警告!
      </div>
    );
  }
class Page extends React.Component{
    constructor(props){
        super(props);
        this.state={showWarning:true}
        this.handleToggleClick=this.handleToggleClick.bind(this)
    }
    handleToggleClick() {
        this.setState(prevState => ({
          showWarning: !prevState.showWarning
        }));
      }
     
      render() {
        return (
          <div>
            <WarningBanner warn={this.state.showWarning} />
            <button onClick={this.handleToggleClick}>
              {this.state.showWarning ? '隐藏' : '显示'}
            </button>
          </div>
        );
      }
}


ReactDOM.render(
    <Page />,
    document.getElementById('example')
  );

React列表&&key

可以使用map()方法创建列表

const numbers=[1,2,3,4,5];
const listItems=numbers.map((number)=>
<li>{number}</li>
);


ReactDOM.render(
    <ul>{listItems}</ul>,
    document.getElementById('example')
)
image.png

重构

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('example')
)

keys

Keys 可以在 DOM 中的某些元素被增加或删除的时候帮助 React 识别哪些元素发生了变化。因此你应当给数组中的每一个元素赋予一个确定的标识。
当元素没有确定的 id 时,你可以使用他的序列号索引 index 作为 key

React组件API

  • 设置状态:setState
  • 替换状态: replaceState
  • 设置属性: setProps
  • 替换属性: replaceProps
  • 强制更新: forceUpdate
  • 获取DOM节点: findDOMNode
  • 判断组件挂载状态: isMounted
class Counter extends React.Component{
    constructor(props) {
        super(props);
        this.state = {clickCount: 0};
        this.handleClick = this.handleClick.bind(this);
    }
    
    handleClick() {
      this.setState(function(state) {
        return {clickCount: state.clickCount + 1};
      });
    }
    render () {
      return (<h2 onClick={this.handleClick}>点我!点击次数为: {this.state.clickCount}</h2>);
    }
  }
  ReactDOM.render(
    <Counter />,
    document.getElementById('example')
  );

React组件生命周期

  • Mounting:已插入真实DOM
  • Updating:正在被重新渲染
  • Unmounting:已移出真实DOM

React Ajax

React 组件的数据可以通过 componentDidMount 方法中的 Ajax 来获取,当从服务端获取数据时可以将数据存储在 state 中,再用 this.setState 方法重新渲染 UI。

当使用异步加载数据时,在组件卸载前使用 componentWillUnmount 来取消未完成的请求。

class UserGist extends React.Component{
    constructor(props){
        super(props);
        this.state={username:'',lastGistUrl:''}
    }

    componentDidMount(){
        this.serverRequest=$.get(this.props.source,function(result){
            var lastGistUrl=result[0];
            this.setState({
                username:lastGistUrl.owner.login,
                lastGistUrl:lastGistUrl.html_url
            });
        }.bind(this));
    }
    componentWillUnmount(){
        this.serverRequest.abort();
    }
    render(){
        return(
            <div>{this.state.username}用户最新的Gist共享地址:
            <a href={this.state.lastGistUrl}>{this.state.lastGistUrl}</a></div>
        )
    }
}


ReactDOM.render(
    <UserGist source="https://api.github.com/users/octocat/gists" />,
    document.getElementById('example')
)

表单与事件

在 HTML 当中,像 <input>, <textarea>, 和 <select> 这类表单元素会维持自身状态,并根据用户输入进行更新。但在React中,可变的状态通常保存在组件的状态属性中,并且只能用 setState() 方法进行更新。

class HelloMessage extends React.Component{
    constructor(props){
        super(props);
        this.state={value:'Hello world'}
        this.handleChange=this.handleChange.bind(this);
    }


    handleChange(event){
        this.setState({
            value:event.target.value
        })
    }
    render(){
        var value=this.state.value;
        return (
            <div>
                <input type="text" value={value} onChange={this.handleChange}/>
                <h4>{value}</h4>
            </div>
        )
    }


}

ReactDOM.render(
    <HelloMessage />,
    document.getElementById('example')
)

通过onchange事件来监听input的变化,并修改state
在组件上使用表单,onChange方法将出发state的跟新并将更新的 值传递到子组件的输入框的value上来重新渲染界面。

Select下拉菜单

在React中,不使用selected属性,而在根select标签上用value属性来表示选中项。

class FlavorForm extends React.Component{
    constructor(props) {
        super(props);
        this.state = {value: 'coconut'};
     
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
      }
    handleChange(event){
        this.setState({value:event.target.value})
    }

    handleSubmit(event){
        alert('Your favorite flavor is:'+this.state.value);
        event.preventDefault();
    }

    render(){
        return (
            <form onSubmit={this.handleSubmit}>
            <label>选择您最喜欢的网站
            <select value={this.state.value} onChange={this.handleChange}>
            <option value="gg">Google</option>
            <option value="rn">Runoob</option>
            <option value="tb">Taobao</option>
            <option value="fb">Facebook</option>
          </select>
            </label>
            <input type="submit" value="提交" />
            </form>
        )
    }
}

ReactDOM.render(
    <FlavorForm />,
    document.getElementById('example')
  );

多个表单

当有多个input元素时,可以通过给每个元素添加一个name属性,来让处理函数根据event.target.value的值来选择做什么。

class Reservation extends React.Component{
    constructor(props){
        super(props);
        this.state={
            isGoing:true,
            numberOfGuest:2
        };
        this.handleInputChange=this.handleInputChange.bind(this);
    }

    handleInputChange(event){
        const target=event.target;
        console.log(target);
        const value=target.type==='checkbox'?target.checked:target.value;
        console.log(value)
        const name=target.name;

        this.setState({
            [name]:value
        });
    }

    render(){
        return (
            <form>
                <label>是否离开?
                <input name="isGoing" type="checkbox" checked={this.state.isGoing}  onChange={this.handleInputChange}>
               </input>
                </label>
                <br />
                <label>
                    访客数:
                    <input name="numberOfGuest" type="number"
                    value={this.state.numberOfGuest}
                    onChange={this.handleInputChange}>
                    </input>
                </label>
            </form>
        )
    }
}

ReactDOM.render(
    <Reservation />,
    document.getElementById('example')
  );

React事件

通过onClick事件来修改数据

class HelloMessage extends React.Component{
    constructor(props){
        super(props);
        this.state={
            value:"Hello Runoob!"}
            this.handleChange=this.handleChange.bind(this);
    }

    handleChange(event){
        this.setState({
            value:'菜鸟教程'
        })
    }

    render(){
        var value=this.state.value;
        return (
            <div>
                <button onClick={this.handleChange}>点我</button>
                <h4>{value}</h4>
            </div>
        )
    }
}

ReactDOM.render(
    <HelloMessage />,
    document.getElementById('example')
  );

当你需要从子组件更新父组件的state时,你需要在父组件通过创建事件句柄(handleChange),并作为prop(updateStateProp)传递到你的组件上。

class Content extends React.Component{
    render(){
        return (
            <div>
                <button onClick={this.props.updateStateProp}>点我</button>
                <h4>{this.props.myDataProp}</h4>
            </div>
        )
    }
}


class HelloMessage extends React.Component{
    constructor(props){
        super(props);
        this.state={
            value:'Hello Runoob!'
        }

        this.handleChange=this.handleChange.bind(this);
    }
    handleChange(event) {
        this.setState({value: '菜鸟教程'})
      }

      render(){
          var value=this.state.value;

        return (
            <div>
                <Content myDataProp={value} updateStateProp={this.handleChange}/>

            </div>
        )
      }

}

ReactDOM.render(
    <HelloMessage />,
    document.getElementById('example')
  );

React Refs

React支持一种非常特殊的属性Ref,可以用来绑定到render()输出的任何组件上。

使用方法

绑定一个ref属性到render的返回值上:
<input ref="myInput" />
在其它代码中,通过this.refs获取支撑示例

var input=this.refs.myInput;
var inputValue=input.value;
var inputRect=input.getBoundingClientRect();

实例
可以通过使用this来获取当前的React组件,或使用ref来获取组件的引用。

class MyComponent extends React.Component{
    handleClick(){
        this.refs.myInput.focus();
    }

    render(){
        return (
            <div>
                <input type="text" ref="myInput" />
                <input type="button" value="点我" onClick={this.handleClick.bind(this)}/>
            </div>
        )
    }

}

ReactDOM.render(
    <MyComponent />,
    document.getElementById('example')
  );

相关文章

网友评论

      本文标题:React的学习

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