英语资料上传管理系统总结

  1. 开启两个react app时,显示Something is already running on port 3000.
    解决:PORT=3001 npm start

  2. Import相对路径引用
    ‘./同一文件夹内文件’
    ‘../父级文件夹兄弟文件’

  3. npm i 依赖安装 报错 error -4058 syscall access
    解决:使用cnpm i

  4. 报错Each child in an array or iterator should have a unique “key” prop.
    原代码

    1
    2
    3
    const imgList = imgStr.map((image) =>
    <li className="icon-wrap"><img src={image} alt=""/></li>react
    );

    修改后

    1
    2
    3
    const imgList = imgStr.map((image,i) =>
    <li className="icon-wrap" key={i}><img src={image} alt=""/></li>
    );
  5. 同一行文字图片不对齐
    解决: 给文字设置vertical-align: top;属性。

  6. ‘props’ is not defined
    解决:props调用前需要加this,{this.props.image}

  7. 修改state数组中某一个

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    constructor(props) {
    super(props);
    this.state = {open: [false,false,false,false,false,false,false,false,false,false]};
    this.handleClick = this.handleClick.bind(this);
    }

    handleClick(i) {
    let state = this.state;
    state[i] = !state[i];
    this.setState({state: state})
    }
  8. Map事件绑定
    需要先将map变量保存在变量中再输出。为什么?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    render() {
    let wideList = listStr.map((it, i) =>
    <li className="list-wrap" key={i} >
    <div className="big-list"
    onClick={this.handleClick.bind(this, i)}>
    <img src={it.image} alt=""/>
    <span>{it.name}</span>
    </div>
    </li>
    return (
    <div className="wider-sidebar">
    <ul>
    {wideList}
    </ul>
    </div>
    );
    }
  9. 子组件向父组件传递数据
    父:父组件传递带参函数,参数为子组件需要向父组件传递的参数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    typeChange(i, typeStr){
    let newType = this.state.type;
    newType[i] = typeStr;
    this.state = {
    type: newType
    };
    }
    <SelectBox typeChange={this.typeChange.bind(this)}/>或者
    <SelectBox typeChange={(i, typeStr) => this.typeChange(i, typeStr)
    }/>

子:子组件调用父组件函数,传入需要传递的参数

1
2
3
4
5
6
7
handleChange(i, e){
this.props.typeChange(i, this.state.type[i]);//调用父组件函数
}
<input type="text"
list={'type' + (index+1)}
value={this.state.type[index]}
onChange={this.handleChange.bind(this,index)}/>

  1. Js函数全角改半角

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    changeMark(str){
    let tmp = "";
    for(let i=0;i<str.length;i++){
    if(str.charCodeAt(i) >= 65281 && str.charCodeAt(i) <= 65374){// 如果位于全角!到全角~区间内
    tmp += String.fromCharCode(str.charCodeAt(i)-65248)
    }else if(str.charCodeAt(i) === 12288){//全角空格的值,它没有遵从与ASCII的相对偏移,必须单独处理
    tmp += ' ';
    }else{// 不处理全角空格,全角!到全角~区间外的字符
    tmp += str[i];
    }
    }
    return tmp;
    }
  2. 按符号分割字符串。
    开始想着是用split,但是split会把标点符号给删了,不行。
    解决1. 用match
    找到与句子匹配的正则
    str.match(reg);直接分割,但是正则表达式没有找着,后续学习。。
    解决2. 函数exec

    1
    2
    3
    4
    5
    let lastindex = 0;
    while((r=reg.exec(articleStr))!==null){
    sentenceArr.push(articleStr.substring(lastindex, r.index+1));
    lastindex=reg.lastIndex;
    }
  3. Constructor中的super什么意思?

  4. React单选框组件

    1
    2
    3
    4
    5
    6
    <input type="radio" name="rightAnswer"
    value={this.state.value}
    checked={this.state.rightAnswer === this.state.value}
    onClick={this.rightAnswerChange.bind(this, index)}
    onChange={this.rightAnswerChange.bind(this, index)}/>
    <label>正确答案</label>
  5. Axios执行post请求时,后来获取不到数据,提示Required XXX parameter XXX is not present.
    先前写法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    let data={
    sentence_contents: sentenceArr,
    lesson_type_id: 1,
    owner_id: 1
    };
    axios.post('https://pay.regiondavid.xyz/Qidian-test/lessonEdit/init_sentences', data,{
    headers: {
    /* 一些公用的 header */
    'X-Requested-With': 'XMLHttpRequest'
    },
    crossDomain: true,
    withCredentials: true
    })
    .then(function (res) {
    console.log(res);
    })
    .catch(function (err) {
    console.log(err);
    })

解决: post参数传递要以
"userName='n'& phone='13'& email='12'& emailPwd='22'& kindleEmail='asd'"
形式传递
而上面传递的为对象格式
解决方案1:

1
2
3
4
let data = new URLSearchParams();
data.append("sentence_contents", '[a,a]');
data.append("lesson_type_id", 1);
data.append("owner_id", 1);

解决方案2:封装一个axios实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import axios from 'axios'

/* 创建一个新的 AXIOS 对象,确保原有的对象不变 */
let axiosWrap = axios.create({
baseURL: 'https://pay.regiondavid.xyz/Qidian-test'/* 服务器的根路径 */,
headers: {
/* 一些公用的 header */
'X-Requested-With': 'XMLHttpRequest',
},
crossDomain: true,
withCredentials: true,
transformRequest:[function (data, header){
/* 自定义请求参数解析方式(如果必要的话)修改传递data格式 */
let ret = '';
for (let it in data) {
ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&';
}
return ret;
}],
export default axiosWrap

调用

1
2
3
4
5
6
7
8
9
10
11
12
let data={
sentence_contents: sentenceArr,
lesson_type_id: 1,
owner_id: 1
};
axiosWrap.post('/lessonEdit/init_sentences',data)
.then(function (res) {
console.log(res);
})
.catch(function (err) {
console.log(err);
})

  1. React中props传递的数据类型为数组时,子组件讲改传递值作为了state并修改了他,父组件中相应数组也会跟着修改。
    父:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class Text1Edit extends Component {
    constructor(props) {
    super(props);
    this.state = {
    sentenceArr: [‘a’,’b’,’c’]
    }
    }
    render() {
    console.log(this.state.sentenceArr);
    return (
    <div className="text1-edit">
    { this.state.sentenceArr }
    </div>
    );
    }
    }

子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class SentenceArea extends Component {
constructor(props) {
super(props);
let sentenceArr = this.props.arr;
sentenceArr.shift();
// console.log(sentenceArr);
this.state = {
title: this.props.arr[0],
sentenceArr: sentenceArr, //句子字符串
// sentences : this.props.arr.substring(1),
firstIndex: NaN,//第一次点击的句子索引

}
}

解决:复杂类型利用=传值传递的均为地址,即所有对象均指向一个地址,修改一个全部都会改变,所以应该在子组件实现深拷贝,即实现数组的一个备份。

  1. Ajax传递复杂对象类型时,如{a:2,b:{a:1,b:2}}时,直接对该data无法编码,需要预先将b对应的对象转为Json字符串,再传递。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    let data = {
    sequence: this.state.sequence,
    type: this.state.type,
    question: this.state.question,
    options: this.state.options,
    answer: this.state.answer
    };
    let dataStr = JSON.stringify(data);
    axiosWrap.post('/lessonEdit/upload_reading_comprehension', {
    reading_comprehension : dataStr,
    lesson_id : this.state.lesson_id
    }).then(res => {
    console.log(res);
    }).catch(err => {
    console.log(err);
    })
  2. Ajax更新父组件State时,传入子组件的props转换为state没有更新,
    解决:
    1.(暴力方法)通过给子组件添加不同的key即可,这样在每次父组件执行render方法的时候,发现key不相同,则会重新加载子组件;

    1
    2
    3
    4
    class Par entend React.PureComponent{
    render(){
    <Son key=Math.random()/> }
    }

2.这种方式,由于我们使用的是state,所以每当父组件每次重新传递props时,我们需要重新处理下,将props转换成自己的state,这里就用到了componentWillReceiveProps。在componentWillReceiveProps中this.props为老的props值,需要引用nextProps获取新的props的值。当父组件的的props更新时,子组件的this.props的值也是从render函数开始执行的时候开始更新的,render之前生命周期函数中都是获取不到最新的this.props的,除非用this.props=nextProps进行更新。
关于你提到的不会二次渲染是这样的:每次子组件接收到新的props,都会重新渲染一次,除非你做了处理来阻止(比如使用:shouldComponentUpdate),但是你可以在这次渲染前,根据新的props更新state,更新state也会触发一次重新渲染,但react不会这么傻,所以只会渲染一次,这对应用的性能是有利的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Child extends Component {
constructor(props) {
super(props);
this.state = {
someThings: props.someThings
};
}
componentWillReceiveProps(nextProps) {
this.setState({someThings: nextProps.someThings});
}
render() {
return <div>{this.state.someThings}</div>
}
}

  1. 不用link利用js实现跳转

    1
    2
    3
    4
    5
    import {withRouter} from "react-router-dom";
    class QuestionEdit extends Component {
    this.props.history.push('/Text2Edit');
    }
    export default withRouter(QuestionEdit);
  2. 对象属性名通过(.)与([])调用区别
    (.)调用时,后面必须为字符串。
    ([])调用时,中间可以为变量。

  3. git过滤文件以及文件夹
    1) 在根目录中创建.gitignore.txt文件,或者在需要创建.gitignore文件的文件夹内进入命令行,输入touch .gitignore即可。
    2) 在.gitignore文件里输入你要忽略的文件夹及其文件就可以了。
    文件夹用bin/表示,文件后缀用*.dll表示.

  4. prevState

    1
    this.setState((prevState)=>({voicePlay: !prevState.voicePlay}))
  5. html5语音控制播放暂停

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    voicePlay(){
    let audio=document.getElementById('audio');
    if (audio.paused) {
    audio.play();
    this.setState({voicePlay: '停止'});
    }else{
    audio.pause();
    audio.currentTime = 0;
    this.setState({voicePlay: '停止'});
    }
    }
    <button onClick={this.voicePlay.bind(this)}>{this.state.voicePlay}</button>
    <audio id='audio'>
    <source src={a} type="audio/mpeg"/>
    </audio>
  6. 动态修改state,封装成函数。

    1
    2
    3
    stateChange(prop, val) {
    this.setState({[prop]: val});
    }
  7. 深拷贝
    深拷贝对象还有另一个解决方法,在对象中不含有函数的时候,使用JSON解析反解析就可以得到一个深拷贝对象

    1
    JSON.parse(JSON.stringify(obj));