React学习1

React重要学习方式:官方文档

React:

(1)声明式开发;(原生js、jQuery命令式开发)

(2)可以与其它框架并存;(比如Vue、jQuery等,每个只负责自己的组件部分)

(3)组件化;(组件首字母大写)

(4)单向数据流;(父可以传给子,子不能修改父的state)

(5)视图层框架----解决数据和页面渲染问题;(大型项目需配合数据层框架flux、redux等----解决组件之间复杂传值问题)

(6)函数式编程。(易维护、有益于前端自动化测试)

1.React 向事件处理程序传递参数的两种方式:

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

上述两种方式是等价的,分别通过 arrow functions 和 Function.prototype.bind 来为特定事件类型添加事件处理程序。

上面两个例子中,参数 e 作为 React 事件对象将会被作为第二个参数进行传递。通过箭头函数的方式,事件对象必须显式的进行传递,但是通过 bind 的方式,事件对象以及更多的参数将会被隐式的进行传递。

值得注意的是,通过 bind 方式向监听函数传参,在类组件中定义的监听函数,事件对象 e 要排在所传递参数的后面。

2.dangerouslySetInnerHTML:使item中的HTML标签起作用,而不是直接显示出来(即不被转义)

3.<label htmlFor="insertArea">输入内容</label>:lable的作用:扩大点击的区域,通过htmlFor将光标聚焦到input

4.Fragment占位符:return下只能有一个标签比如div,若要不想显示最外层div,用Fragment替代它

5.事件触发的方法需要用bind绑定this,且方法后不加();直接需要执行的方法不用bind绑定this,方法后加()。

bind绑定必须在使用函数之前。

<button onClick={this.handleButtonClick}>提交</button>

<ul>{this.getTodoItem()}</ul>

getTodoItem(){
        return(
            this.state.list.map((item, index) => {
                return (
                    <div>
                        <TodoItem content={item} index={index} deleteItem={this.handleItemDelete}/>
                    </div>
                )
            })
        )
    }


handleButtonClick() {
        this.setState({
            inputValue: '',
            list: [...this.state.list, this.state.inputValue]
        })
    }

6.在jsx中做循环时(比如map循环返回新数组、子组件时),对循环中的每一项(最外层的)都要赋予一个唯一的key值。

不要用index作为key值,因为index有可能会改变(比如删除数组中的一个元素时)。

getTodoItem() {
        return (
            this.state.list.map((item, index) => {
                return (
                    <TodoItem key={index} content={item} index={index} deleteItem={this.handleItemDelete}/>
                )
            })
        )
    }

***组件拆分和组件之间的传值

(1)父子组件之间如何传递参数、方法?

父组件中通过设置子组件的属性传递参数、方法;子组件通过props接受参数、方法。

(2)子组件如何更改父组件中的state?

在父子组件结构中,采用状态提升故父组件中的state由父组件的方法更改;若子组件想改变state,通过方法下放

(3)子组件如何调用父组件中的方法?----方法下放

1.父组件将方法通过子组件属性传递给子组件(传递前,须将方法的this指向绑定到父组件上)。

2.子组件通过props调用该方法(该方法可以实现对父state的改变,即实现子组件改变父组件中的state)(调用时可向该方法传递想传递的参数)。

实例分析:TodoList

(1)index.js

import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList';

ReactDOM.render(<TodoList />, document.getElementById('root'));

(2.1)TodoList.js(没采用父子组件结构)

import React, {Component, Fragment} from 'react';
import './style.css';
import TodoItem from './TodoItem';

class TodoList extends Component {
    constructor(props) {
        super(props)
        this.state = {
            inputValue: '',
            list: []
        }
        this.handleItemDelete=this.handleItemDelete.bind(this);
    }

    render() {
        return (
            // Fragment占位符,return下只能有一个标签比如div,若要不想显示最外层div,用Fragment替代它
            <Fragment>
                <div>
                    <label htmlFor="insertArea">输入内容</label>
                    {/*lable的作用:扩大点击的区域,通过htmlFor将光标聚焦到input*/}
                    <input id={'insertArea'} className={'input'} value={this.state.inputValue}
                           onChange={(e) => this.handleInputChange(e)}/>
                    {/*<input value={this.state.inputValue} onChange={this.handleInputChange.bind(this)}/>*/}
                    <button onClick={() => this.handleButtonClick()}>提交</button>
                </div>
                <ul>
                    {   //根据list中内容将其渲染到ul中
                        // 经过map()方法后将原list: ['React','vue']数组变为['<li>React</li>','<li>vue</li>']
                        this.state.list.map((item, index) => {
                            return (
                                    <li key={index}
                                        onClick={(e) => this.handleItemDelete(index, e)}
                                        dangerouslySetInnerHTML={{__html: item}}
                                        //dangerouslySetInnerHTML:使item中的HTML标签起作用,而不是直接显示出来
                                    >
                                    </li>
                            )
                        })
                    }
                </ul>
            </Fragment>
        )
    }

    handleInputChange(e) {
        // this.setState({
        //     inputValue: e.target.value
        // })
        this.setState(()=>{
            return{
                inputValue: e.target.value
                }
            })
    }

    handleButtonClick() {
        // this.setState({
        //     inputValue: '',
        //     list: [...this.state.list, this.state.inputValue]
        // })
        this.setState(()=>{
            return{
                inputValue: '',
                list: [...this.state.list, this.state.inputValue]
            }
        })
    }

    handleItemDelete(index) {
        const list = [...this.state.list];
        list.splice(index, 1);
        // this.setState({
        //     list: list
        // })
        this.setState(()=>{
            return{
                list: list
            }
        })
    }
}

export default TodoList;

(2.2)TodoList.js(采用父子组件结构----父组件

import React, {Component, Fragment} from 'react';
import './style.css';
import TodoItem from './TodoItem';

class TodoList extends Component {
    constructor(props) {
        super(props)
        this.state = {
            inputValue: '',
            list: []
        }
        this.handleItemDelete=this.handleItemDelete.bind(this);
    }

    render() {
        return (
            // Fragment占位符,return下只能有一个标签比如div,若要不想显示最外层div,用Fragment替代它
            <Fragment>
                <div>
                    <label htmlFor="insertArea">输入内容</label>
                    {/*lable的作用:扩大点击的区域,通过htmlFor将光标聚焦到input*/}
                    <input id={'insertArea'} className={'input'} value={this.state.inputValue}
                           onChange={(e) => this.handleInputChange(e)}/>
                    {/*<input value={this.state.inputValue} onChange={this.handleInputChange.bind(this)}/>*/}
                    <button onClick={() => this.handleButtonClick()}>提交</button>
                </div>
                <ul>
                    {   //根据list中内容将其渲染到ul中
                        // 经过map()方法后将原list: ['React','vue']数组变为['<li>React</li>','<li>vue</li>']
                        this.state.list.map((item, index) => {
                            return (
                                 <TodoItem content={item} index={index} deleteItem={this.handleItemDelete}/>
                                //由于单向数据流,这里不能直接将state中的list传给子组件,子组件不能直接修改state。
                            )
                        })
                    }
                </ul>
            </Fragment>
        )
    }

    handleInputChange(e) {
        this.setState({
            inputValue: e.target.value
        })
    }

    handleButtonClick() {
        this.setState({
            inputValue: '',
            list: [...this.state.list, this.state.inputValue]
        })
    }

    handleItemDelete(index) {
        const list = [...this.state.list];
        list.splice(index, 1);
        this.setState({
            list: list
        })
    }
}

export default TodoList;

(3)TodoItem.js(采用父子组件结构----子组件)

import React from 'react';

class TodoItem extends React.Component{
    constructor(props){
        super(props);
        this.handleClick=this.handleClick.bind(this);
    }

    shouldComponentUpdate(nextProps, nextState){
        if(nextProps.content !== this.props.content){
            return true;
        }else{
            return false;
        }
    }    

    render() {
        return(
            <div onClick={this.handleClick}>{this.props.content}</div>
        )
    }
    handleClick(){
        this.props.deleteItem(this.props.index);
    }
}

export default TodoItem;

****TodoList优化后的代码:

(1)TodoList.js

import React, {Component, Fragment} from 'react';
import TodoItem from './TodoItem';
import './style.css';

class TodoList extends Component {
    constructor(props) {
        super(props)
        this.state = {
            inputValue: '',
            list: []
        }
        this.handleInputChange = this.handleInputChange.bind(this);
        this.handleButtonClick = this.handleButtonClick.bind(this);
        this.handleItemDelete = this.handleItemDelete.bind(this);
    }

    render() {
        return (
            <Fragment>
                <div>
                    <label htmlFor="insertArea">输入内容</label>
                    <input id={'insertArea'}
                           className={'input'}
                           value={this.state.inputValue}
                           onChange={this.handleInputChange}/>
                    <button onClick={this.handleButtonClick}>提交</button>
                    {/*事件触发的方法需要用bind绑定this; 且方法后不加()*/}
                </div>
                <ul>{this.getTodoItem()}</ul>
                {/*直接需要执行的方法不用bind绑定this; 方法后加()*/}
            </Fragment>
        )
    }

    getTodoItem() {
        return (
            this.state.list.map((item, index) => {
                return (
                    <TodoItem key={index} content={item} index={index} deleteItem={this.handleItemDelete}/>
                )
            })
        )
    }

    handleInputChange(e) {
        const value = e.target.value;
        this.setState(() => ({
                inputValue: value
            })
        )
    }

    handleButtonClick() {
        this.setState((prevState) => ({
                inputValue: '',
                list: [...prevState.list, prevState.inputValue]
            })
        )
    }

    handleItemDelete(index) {
        this.setState((prevState) =>{
            const list = [...prevState.list];
            list.splice(index, 1);
            return {list: list}
            }
        )
    }
}

export default TodoList;

(2)TodoItem.js

import React from 'react';

class TodoItem extends React.Component{
    constructor(props){
        super(props);
        this.handleClick=this.handleClick.bind(this);
    }
    render() {
        const {content}=this.props;  //ES6的解构赋值
        return(
            <div onClick={this.handleClick}>{content}</div>
        )
    }
    handleClick(){
        const {deleteItem, index}=this.props;  //ES6的解构赋值
        deleteItem(index);
    }
}

export default TodoItem;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值