React基础(CDN方式)

React(CDN方式)

一、依赖说明配置

1.依赖引入(react16版本,这里是)

  <!-- 需要在引入 React拓展库之前引入 React核心库-->

    <!-- React核心库 -->
    <script src="../js/react.development.js"></script>

    <!-- 引入react-dom 用于支持react操作DOM -->
    <script src="../js/react-dom.development.js"></script>

    <!-- 引入babel 用于将jsx转换成js -->
    <script src="../js/babel.min.js"></script>

#二、老样子,Hello React,jsx的语法(运行时,会编译成js)

<body>
    <div id="app">

    </div>
    <script type="text/babel"> /* 此处一定要写 type="text/babel"*/
        const my_id = 'aTGuiGu';
        const my_data = 'Hello React';
       
        const VDOM = (   /* 此处不需要写引号,应为不是字符串 */
            <h3 className="red" id={my_id.toLocaleLowerCase()}>
                <span style={{color:'red'}}>{my_data}</span>
            </h3>
        )
        
       
        ReactDOM.render(VDOM, document.querySelector('#app'));

       
    </script>
</body>

a.注意点(渲染DOM分两步)

 // 1.创建虚拟DOM 
	const VDOM = <h2>hello React</h2>
 // 2.渲染虚拟DOM到页面
     ReactDOM.render(VDOM, document.querySelector('#app'));
 	    // 1.在虚拟DOM中渲染数据时,使用{},只能填写能返回一个值的表达式
        // 2.样式的类名指定不要用class,要用className
        // 3.内敛样式,使用style={{key:value}}的形式,多个单词属性使用小驼峰
        // 4.虚拟DOM只能有一个根标签
        // 5.标签必须闭合
        // 6.标签首字母大写,表示使用组件,小写直接转换成html标签,转换失败时,报错

1.在js中渲染虚拟DOM

// 1.创建虚拟DOM 
const VDOM = React.createElement('h3',{id:'title'},React.createElement('span',{},'Hello React'))
// 2.渲染虚拟DOM到页面
ReactDOM.render(VDOM, document.querySelector('#app')); 

2.React自动遍历虚拟DOM中数组

<script type="text/babel">
        const data = ['Angular','React','Vue'];
    
        const VDOM = (
            <div>
                <h1>前端js框架列表</h1>
                <ul>
                    {data.map((item,index)=><li key={index}>{item}</li>)}
                </ul>
            </div>
        );
        ReactDOM.render(VDOM,document.getElementById('app'))
 </script>

二、组件定义

1.函数式组件定义

<script type="text/babel">
        
        function ChirldComponent(){
            console.log(this); // 此处的this是undefined,因为babel编译开启后开启了严格模式
            return <h3>This is a chirld component</h3>
        }
    
        ReactDOM.render(<ChirldComponent/>,document.getElementById('app'))
        
        // 1. React解析组件标签,找到了ChirldComponent组件
        // 2. 调用函数,返回的虚拟DOM渲染成真实DOM呈现在页面中
        
    </script>
</body>

2.类是组件

// 1. 创建类式组件
        class ChirldComponent extends React.Component {
            render() {
                console.log(this)
                return (
                    <div>
                        我是类式组件
                    </div>
                )
            }
        };
        ReactDOM.render(<ChirldComponent/>,document.getElementById('app'))
        
        // 1. React解析组件标签,找到了ChirldComponent组件
        // 2. new 出该类的实例,调用实例的render()
        // 3. 将返回的虚拟DOM渲染成真实DOM呈现在页面中

三、组件三大属性

1.组件state属性

注意:
1.组件中render方法中的this为组件实例对象
2.组件自定义的方法中this为undefined,如何解决?
a)强制绑定this: 通过函数对象的bind()
b)箭头函数
3.状态数据,不能直接修改或更新
<script type="text/babel">
        class Weather extends React.Component {
            /*constructor(props) {
                super(props);
                this.state = {
                    isHot: true,
                    wind:'微风'
                };
            }*/
            state = {
                    isHot: true,
                    wind: '微风'
                }
            render() {
                // 每次渲染都会调用 render
                const { isHot,wind } = this.state;
                return (
                    <h3 ref="title" onClick={this.changeHot.bind(this)}>
                        今天天气很{isHot ? '炎热' : '寒冷'},{wind}
                    </h3>
                )
            }
            changeHot() {
                // 该函数由window调用,因为类中的方法默认开启了严格模式,so 这里this=>undefined
                this.setState({
                    isHot:!this.state.isHot
                });
            }

        };
        ReactDOM.render(<Weather />, document.getElementById('app'));

    </script>

2.组件props属性

a.新的依赖引入


    <!-- 用于对组件标签属性进行限制 -->
    <script src="../js/prop-types.js"></script>

b.props在子组件中基本使用

标签体内容,就是标签的children属性,可以在props获取
<script type="text/babel">
        class Person extends React.Component {

            // 对组件属性进行类型、必要性的限制
            static propTypes = {
                name: PropTypes.string.isRequired,
                age:PropTypes.number,
                sex:PropTypes.string,
                speak:PropTypes.func
            }

            // 指定标签属性默认值
            static defaultProps = {
                sex:'0',
                age:18
            }
            render() {
                let { name, age, sex } = this.props;
                return (
                    <ul>
                        <li>姓名:{name}</li>
                        <li>性别:{sex == 1 ? '男' : '女'}</li>
                        <li>年龄:{age + 1}</li>
                    </ul>
                )
            }
        }
        ReactDOM.render(<Person name="Jone" speak={speak} />, document.getElementById('app'));

        function speak(){
            console.log('我说话了');
        }

    </script>

c.props是否在构造器中使用

   constructor(props){
                // 是否将接收到props传递给super,取决于是否希望在构造器中通过this访问props
                super(props);
                console.log(this.props);
            }
// 建议:一般不写contructor函数

d.在函数式组件中使用props属性

 
<script type="text/babel"> 
        Person.propTypes = {
            name: PropTypes.string.isRequired,
            age: PropTypes.number,
            sex: PropTypes.string,
            speak: PropTypes.func
        }
        Person.defaultProps = {
            sex: '0',
            age: 18
        }
        function Person(props) {
            let { name, sex, age } = props;
            return (
                <ul>
                    <li>姓名:{name}</li>
                    <li>性别:{sex == 1 ? '男' : '女'}</li>
                    <li>年龄:{age + 1}</li>
                </ul>
            )
        }
        ReactDOM.render(<Person name="Jone" speak={speak} />, document.getElementById('app'));

        function speak() {
            console.log('我说话了');
        }

    </script>

3.组件refs属性

a.refs_字符串类型

​ 跟vue的refs相似,但官方已经不建议了,影响性能,建议避免这种方式使用ref

<script type="text/babel">
        class Demo extends React.Component {
            render() {
                return (
                    <div>
                        <input ref="input1" type="text" placeholder="点击按钮提示数据"/>
                        <button onClick={this.showData}>点我提示数据</button>&nbsp;&nbsp;&nbsp;&nbsp;
                        <input onBlur={this.showData2} ref="input2" type="text" placeholder="失去焦点提示数据"/>
                    </div>
                )
            }
            showData = ()=>{
                alert(this.refs.input1.value);
            }
            showData2 = ()=>{
                alert(this.refs.input2.value);
            }
        }

        ReactDOM.render(<Demo />,document.getElementById('app'));

    </script>

b.refs_回调函数

​ 就是利用回调函数,直接将传给回调函数的参数(真实DOM对象),赋值给组件对象的一个属性

   <script type="text/babel">
        class Demo extends React.Component {
            state = {
                num: 1
            }
            render() {
                // 内联式回调函数,每次渲染时React会自动调用两次ref的回调函数,第一次传值为null,第二次传值的DOM节点对象
                return (
                    <div>
                        {this.state.num}
                        {/* <input ref={el =>{ console.log(el);this.input1 = el}} type="text" placeholder="点击按钮提示数据" />*/}
                        <input ref={this.saveInput} type="text" placeholder="点击按钮提示数据" />
                        <button onClick={this.showData}>点我提示数据</button>&nbsp;&nbsp;&nbsp;&nbsp;
                    </div>
                )
            }
            showData = () => {
                let { num } = this.state;
                this.setState({
                    num: num + 1
                })
            }
            saveInput = (c) => {
                this.input1 = c;
                console.log(c);
            }
        }

        ReactDOM.render(<Demo />, document.getElementById('app'));

    </script>

c.refs_中的createRef

​ 缺点,每次需要使用ref标记对象时,都需要提起定义装载ref的容器,newRef = React.createRef(),使用方式ref对象与回调函数类似

<script type="text/babel">
        class Demo extends React.Component {
            state = {
                num: 1
            }
            myRef = React.createRef();
            myRef2 = React.createRef();
            render() {
                return (
                    <div>
                        {this.state.num}
                        <input ref={this.myRef} type="text" placeholder="点击按钮提示数据" />
                        <button onClick={this.showData}>点我提示数据</button>&nbsp;&nbsp;&nbsp;&nbsp;
                        <input ref={this.myRef2} type="text" onBlur={this.showData2} placeholder="失去焦点提示数据" />
                    
                    </div>
                )
            }
            showData = () => {
                let { num } = this.state;
                this.setState({
                    num: num + 1
                })
                console.log(this.myRef.current.value);
            }
            showData2 = ()=>{
                console.log(this.myRef2.current.value);
            }
        }

        ReactDOM.render(<Demo />, document.getElementById('app'));

    </script>

四、事件处理

a.基本使用

<script type="text/babel">
        class Demo extends React.Component {
            myRef = React.createRef();
            render() {
                return (
                    <div>
                        <input ref={this.myRef} type="text" placeholder="点击按钮提示数据" />
                        <button onClick={this.showData}>点我提示数据</button>&nbsp;&nbsp;&nbsp;&nbsp;
                        <input  type="text" onBlur={this.showData2} placeholder="失去焦点提示数据" />

                    </div>
                )
            }
            showData = () => {
                console.log(this.myRef.current.value);
            }
            showData2 = (event) => {
                console.log(event.target.value)
            }
        }

        ReactDOM.render(<Demo />, document.getElementById('app'));

    </script>

b.注意点

/* (1).通过onXxx属性指定事件处理函数(注意大小写)
     a.React使用的是自定义(合成)事件,而不是使用的原生DOM事件     --- 为了更好的兼容性
     b.React中的事件是通过事件委托方式处理的(委托给组件最外层的原生DOM事件)      --- 为了高效
 (2).通过event.target得到发生事件的DOM元素对象       -- 不要过度使用ref
 */

五、收集表单

1.非受控表单

​ 非受控组件,只在提交表单时获取数据

<script type="text/babel">
        class Login extends React.Component {
            username = React.createRef();
            password = React.createRef();

            render() {
                return (
                    <form action="http://www.baidu.com" onSubmit={this.submitUserInfo}>
                        <input ref={this.username} type="text" name="username" placeholder="Enter username ..." /><br/>
                        <input ref={this.password} type="text" name="password" placeholder="Enter password ..."/><br/>
                        <button>登录</button>
                    </form>
                )
            }
            submitUserInfo = (e)=>{
                e.preventDefault();
                alert(`用户名:${this.username.current.value}\n密码:${this.password.current.value}`);
            }
        }

        ReactDOM.render(<Login />, document.getElementById('app'));

    </script>

2.受控表单

 <!-- 受控组件,实时将组件的输入维护到组件状态中 -->
    <!-- 函数的柯里化:通过通过函数调用继续返回函数的方式,实现多个接收参数,最后统一处理的函数编码形式 -->
    <script type="text/babel">
        class Login extends React.Component {

            // 初始化状态
            state = {
                username: '',
                password: ''
            }
            render() {
                return (
                    <form action="http://www.baidu.com" onSubmit={this.submitUserInfo}>
                        <input onChange={this.saveFormItem('username')} type="text" name="username" placeholder="Enter username ..." /><br />
                        <input onChange={this.saveFormItem('password')} ref={this.password} type="text" name="password" placeholder="Enter password ..." /><br />
                        {/*<input onChange={(e) => this.saveFormItem('username',e)} type="text" name="username" placeholder="Enter username ..." /><br />*/}
                        <button>登录</button>
                    </form>
                )
            }
            saveFormItem = (formItem) => {
                // let formItem = e.target.getAttribute('name');
                // this.setState({
                //     [formItem]:e.target.value
                // })
                return (event) => {
                    this.setState({
                        [formItem]: event.target.value
                    })
                }
            }
            // saveFormItem = (formType, e) => {
            //     this.setState({
            //         [formType]: e.target.value
            //     })
            // }
            submitUserInfo = (e) => {
                e.preventDefault();
                let { username, password } = this.state;
                alert(`用户名:${username}\n密码:${password}`);
            }
        }

        ReactDOM.render(<Login />, document.getElementById('app'));

    </script>

六、生命周期

1.旧生命周期(React_16)

a.图示

请添加图片描述

b.代码测试

<script type="text/babel">
        class Count extends React.Component {
            state = {
                count: 0
            }
            constructor(props) {
                super(props);
                console.log('constructor');
            }
            add = (e) => {
                const { count } = this.state;
                this.setState({
                    count: count + 1
                })
            }
            death = () => {
                ReactDOM.unmountComponentAtNode(document.getElementById('app'));
            }
            force = () => {
                this.forceUpdate();
            }
            componentWillMount() {
                console.log('componentWillMount');
            }
            render() {
                console.log('render');
                const { count } = this.state;
                return (
                    <div>
                        <h2>当前求和为{count}</h2>
                        <button onClick={this.add}>点我加1</button>
                        <button onClick={this.death}>unmount</button>
                        <button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
                    </div>
                )
            }
            componentDidMount() {
                console.log('componentDidMount')
            }

            shouldComponentUpdate(...args) {
                console.log('shouldComponentUpdate');
                // 为true 时,才会去更新页面,调用render();
                return false;
            }
            componentWillUpdate() {
                console.log('componentWillUpdate');
            }
            componentDidUpdate() {
                console.log('componentDidUpdate');
            }
            componentWillUnmount() {
                console.log('componentWillUnmount');
            }
        }

        class A extends React.Component {
            state ={ carName:'奔驰'}
            changeCar = ()=>{
                this.setState({
                    carName:'奥托'
                })
            }
            render() {
                return (
                    <div>
                        <div>我是A组件</div>
                        <button onClick={this.changeCar}>换车</button>
                        <B carName={this.state.carName}/>
                    </div>
                )
            }
        }
        class B extends React.Component {
            // 首次传递props不会调用该钩子
            componentWillReceiveProps(props){
                console.log('B--componentWillReceiveProps',props)
            }

            shouldComponentUpdate(){
                console.log('B-shouldComponentUpdate');
                return true;
            }
            componentWillUpdate() {
                console.log('B-componentWillUpdate');
            }
            componentDidUpdate() {
                console.log('B-componentDidUpdate');
            }
            render() {
                return (
                    <div>我是B组件,{this.props.carName}</div>
                )
            }
        }

        ReactDOM.render(<A />, document.getElementById('app'));
    </script>

c.生命周期流程

1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
    1.constructor()
    2.componentWillMount()
    3.render()
    4.componentDidMount()
2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
    1.shouldComponentUpdate()
    2.componentWillUpdate()
    3.render()
    4.componentDidUpdate()
3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
	componentWillUnmount()

2.新生命周期(React_17)

a.图示

请添加图片描述

b.代码测试

<script type="text/babel">
        class Count extends React.Component {
            state = {
                count: 0
            }
            constructor(props) {
                super(props);
                console.log('constructor');
            }
            add = (e) => {
                const { count } = this.state;
                this.setState({
                    count: count + 1
                })
            }
            death = () => {
                ReactDOM.unmountComponentAtNode(document.getElementById('app'));
            }
            force = () => {
                this.forceUpdate();
            }


            // 必须返回一个状态或者null, 若state的值在任何时都取决于props,那么可以使用getDerivedStateFromProps
            // static getDerivedStateFromProps(props, state) {
            //     console.log('getDerivedStateFromProps', props, state);
            //     // return props;
            //     return null;
            // }
            shouldComponentUpdate(...args) {
                console.log('shouldComponentUpdate');
                // 为true 时,才会去更新页面,调用render();
                return true;
            }

            render() {
                console.log('render');
                const { count } = this.state;
                return (
                    <div>
                        <h2>当前求和为{count}</h2>
                        <button onClick={this.add}>点我加1</button>
                        <button onClick={this.death}>unmount</button>
                        <button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
                    </div>
                )
            }

            // 更新之前的快照,可用于返回一个值,例如:保留之前滚轮的位置,返回值传递给componentDidUpdate
            getSnapshotBeforeUpdate(...args){
                console.log('getSnapshotBeforeUpdate',args);
                return 'jiang';
            }

            componentDidMount() {
                console.log('componentDidMount')
            }


            componentDidUpdate(preProps,preState,SnapshotValue) {
                console.log('componentDidUpdate',{preProps,preState,SnapshotValue});
            }
            componentWillUnmount() {
                console.log('componentWillUnmount');
            }
        }
        ReactDOM.render(<Count count='199' />, document.getElementById('app'));
    </script>

3.生命周期(getSnapshotBeforeUpdate使用)

​ 保持浏览时内容不滑动,保留之前浏览位置

css

<style>
        .news_list {
            width: 200px;
            height: 150px;
            border: solid 1px gray;
            overflow: auto;
        }

        .news {
            height: 30px;
        }
   </style>

jsx

<script type="text/babel">
        class NewsList extends React.Component {
            state = {
                newsArr:[]
            }
            list = React.createRef();
            componentDidMount(){
                setInterval(()=>{
                    let {newsArr} = this.state;
                    const news = '新闻' + (newsArr.length + 1);
                    this.setState({
                        newsArr:[news,...newsArr]
                    })
                },1000)
            }
            render() {
                return (
                    <div className="news_list" ref={this.list}>
                        {this.state.newsArr.map((n,index)=>{
                            return (
                                <div className="news" key={index}>{n}</div>
                            )
                        })}
                    </div>
                )
            }
            getSnapshotBeforeUpdate(){
                return this.list.current.scrollHeight;
            }
            componentDidUpdate(prevProps,prevState,prevHeight){
                this.list.current.scrollTop += this.list.current.scrollHeight - prevHeight;
            }
        }
        ReactDOM.render(<NewsList />,document.getElementById('app'));
    </script>

效果:不断产生新的新闻时,保留之前浏览位置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FeHQab7T-1648391539895)(C:\Users\小江\AppData\Roaming\Typora\typora-user-images\image-20220327222119065.png)]

七、其它

1.DOM的Diffing算法

​ 在新旧虚拟DOM比较时,会忽略输入元素的输入,Diffing对比的最小粒度时节点,且时深层次比较

<script type="text/babel">
        class Time extends React.Component {
            state = { date: new Date() }
            componentDidMount() {
                setInterval(() => {
                    this.setState({
                        date: new Date()
                    })
                }, 1000);
            }
            render() {
                return (
                    <div>
                        <h1>hello</h1>
                        <input type="text" />
                        <span>
                            现在是:{this.state.date.toTimeString()}
                            <input type="text" />
                        </span>
                    </div>
                )
            }
        }
        ReactDOM.render(<Time />, document.getElementById('app'));
    </script>

2.key的作用

循环节点中由输入的节点时,数据逆序插入是,必须用数据的id,不能用key,
当只有数据展示时,末尾添加数据,可用key=index
结论,最好别用key = index,用id= key
推荐一个生成唯一标识的库 uuid.js

代码验证

<script type="text/babel">
        // Diffing对比的最小粒度时节点
        // 循环节点中由输入的节点时,数据逆序插入是,必须用数据的id,不能用key,
        // 当只有数据展示时,末尾添加数据,可用key=index
        // 结论,最好别用key = index,用id= key
        class Person extends React.Component {
            state = {
                persons: [
                    { id: 1, name: '小张', age: 18 },
                    { id: 2, name: '小李', age: 19 }
                ]
            }
            render() {
                return (
                    <div>
                        <h2>展示人员信息key = id</h2> 
                        <ul>
                            {this.state.persons.map((item, index) => {

                                return <li key={item.id}><input type="text" /> {item.name}--{item.age}</li>
                            })}
                        </ul>
                        <button onClick={this.addPeron}>添加一个小王</button>
                        <h2>展示人员信息key = index</h2> 
                        <ul>
                            {this.state.persons.map((item, index) => {

                                return <li key={index}><input type="text" /> {item.name}--{item.age}</li>
                            })}
                        </ul>
                        <button onClick={this.addPeron}>添加一个小王</button>
                    </div>

                )
            }
            addPeron = ()=>{
                let {persons} = this.state;
                const p = {id:persons.length + 1,name:'小刘',age:23};
                this.setState({
                    persons:[p,...persons]
                })
            }
        }
        ReactDOM.render(<Person />, document.getElementById('app'));
    </script>
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值