简体   繁体   English

在 React.js APP 中,我发现了这个:TypeError: Cannot set property 'onclick' of null

[英]In a React.js APP, I caught this: TypeError: Cannot set property 'onclick' of null

I am trying to build a webpage that has a calculator on it with react.js.我正在尝试使用 react.js 构建一个带有计算器的网页。 But this message keeps showing up and I don't think moving the relative JS codes to to the end of my scripts would help (or maybe I didn't find a proper way to put it to the end), because react.js requires a return part at the end.但是这条消息不断出现,我认为将相关的 JS 代码移动到我的脚本末尾不会有帮助(或者我没有找到合适的方法将它放到末尾),因为 react.js 需要最后的返回部分。

How to fix it?如何解决?

These are the relative codes:这些是相关代码:

// HTML part (in JSX style)
    <button class="btn" id="compute" >Compute</button>
    <button class="btn" id="reset"   >Reset</button>

// JS part
    var show = document.getElementById("show")
    var btnCompute = document.getElementById("compute")
    var btnReset = document.getElementById("reset")

    btnCompute.onclick = function () {
    // function toCompute () {
        if(expStr){
            show.innerHTML = computeSuffix(nifix2Suffix(strSplit(expStr)));
            expStr = "";
        }
    }

    btnReset.onclick = function () {
    // function toReset () {

        show.innerHTML = "type in here";
        expStr = "";
    }

And the error page is like this: error info错误页面是这样的: error info

The entire codes are as below:整个代码如下:

import React from "react";

class Calculator extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            equ: '',
            answer: 0
        }
    }

    componentDidMount() {
        // Bind <li> to event
        var liList = document.getElementsByTagName("li");
        var expStr = "";

        for (let i = 0; i < liList.length; i++) {
            let li = liList[i];
            li.onclick = () => {
                // 获取中缀表达式(nifix expression)
                expStr += this.textContent;

                // 在页面上显示表达式
                show.innerHTML = expStr;

                // console.log(expStr);
            }
        }

        // 当点击 'Compute' 按钮(id='compute')时
        var show = document.getElementById("show")
        var btnCompute = document.getElementById("compute")
        var btnReset = document.getElementById("reset")

        btnCompute.onclick = function () {
            // function toCompute () {
            if (expStr) {
                show.innerHTML = computeSuffix(nifix2Suffix(strSplit(expStr)));
                expStr = "";
            }
        }

        btnReset.onclick = function () {
            // function toReset () {

            show.innerHTML = "请输入计算式";
            expStr = "";
        }

        // 按键触发事件
        document.onkeypress = function (evt) {
            // 获取按键值
            console.log(evt.key)

            if (evt.key === "Enter") {
                // 'Enter'
                show.innerHTML = computeSuffix(nifix2Suffix(strSplit(expStr)))
                expStr = ""
            } else {
                // 其他按键
                expStr += evt.key
                show.innerHTML = expStr
            }

            // console.log(expStr, "expStr")
        }


        // ======================
        // nifix exp: string => array
        // ======================

        // 表达式分割
        function strSplit(expStr) {
            // 操作数左下标
            var index = 0, list = [];

            for (var i = 0; i < expStr.length; i++) {
                // 忽略空格
                if (expStr[i] === " ") {
                    continue;
                }

                // 如果是操作符
                // 1. 先将操作符前的操作数加入到数组中(判断是否为空)
                // 2. 再将操作符本身加入到数组中
                // 3. 将左下标后移一位
                if ("+-*/()".indexOf(expStr[i]) !== -1) {
                    if (expStr.slice(index, i)) {
                        list.push(expStr.slice(index, i));
                    }
                    list.push(expStr[i]);

                    index = i + 1;
                }
            }

            // 循环结束判断是否存在最后一位操作数,存在,加入数组
            if (i === expStr.length && expStr.slice(index, i)) {
                list.push(expStr.slice(index, i));
            }
            return list;
        }

        // =====================
        // 中缀表达式 => 后缀表达式
        // =====================
        function nifix2Suffix(exlist) {

            // 栈的创建
            var opStack = {
                value: [],
                push: function (item) { this.value.push(item) },
                pop: function () { return this.value.pop() },
                peek: function () { return this.value[this.value.length - 1] },
                isEmpty: function () { return this.value.length === 0 },
                size: function () { return this.value.length }
            }

            // 定义优先级判断
            var dicPriority = {};
            dicPriority['*'] = 3;
            dicPriority['/'] = 3;
            dicPriority['+'] = 2;
            dicPriority['-'] = 2;
            dicPriority['('] = 1;

            // 列表存储转换的后缀表达式
            var suffix = [];

            for (var i of exlist) {

                if ("+-*/()".indexOf(i) === -1) {
                    // 操作数直接添加到列表中
                    suffix.push(i)

                } else if (i === "(") {
                    opStack.push(i)
                } else if (i === ")") {
                    while (opStack.peek() !== "(") {
                        suffix.push(opStack.pop())
                    }
                    opStack.pop()
                } else {
                    while (!opStack.isEmpty() && dicPriority[opStack.peek()] >= dicPriority[i]) {
                        suffix.push(opStack.pop())
                    }
                    opStack.push(i)
                }
            }

            while (!opStack.isEmpty() && opStack.peek() !== "") {
                suffix.push(opStack.pop())
            }

            // console.log(suffix, "后缀数组")

            return suffix
        }

        // var prefix = "a+b*c+(d*e+f)*g"

        // console.log(nifix2Suffix(prefix))
        // 检验栈对象是否成功
        // console.log(opStack.value)
        // console.log(opStack.push(5))
        // console.log(opStack.value)
        // console.log(opStack.push(10))
        // console.log(opStack.peek())
        // console.log(opStack.isEmpty())
        // console.log(opStack.size())
        // console.log(opStack.value)



        // ============
        // 后缀表达式计算
        // ============
        function computeSuffix(exlist) {

            // 如果接收的是空数组
            // 代表表达式错误 / 用户未输入
            if (exlist.length === 0) {
                return "请输入正确的表达式"
            }

            // 栈的创建
            var opStack = {
                value: [],
                push: function (item) { this.value.push(item) },
                pop: function () { return this.value.pop() },
                peek: function () { return this.value[this.value.length - 1] },
                isEmpty: function () { return this.value.length === 0 },
                size: function () { return this.value.length }
            }

            for (var i = 0; i < exlist.length; i++) {
                // 遍历表达式
                switch (exlist[i]) {
                    case "+":
                        opStack.push(opStack.pop() + opStack.pop())
                        break
                    case "-":
                        var jianshu = opStack.pop()
                        opStack.push(opStack.pop() - jianshu)
                        break
                    case "*":
                        opStack.push(opStack.pop() * opStack.pop())
                        break
                    case "/":
                        var chushu = opStack.pop()
                        opStack.push(opStack.pop() / chushu)
                        break
                    default:
                        opStack.push(parseFloat(exlist[i]))
                }
            }

            var result = opStack.pop()

            // console.log(result, "后缀结果")

            if (isNaN(result)) {
                return "计算出错啦!"
            }
            return result % 1 === 0 ? result : result.toFixed(2)
        }

    }

    render() {
        return (
            <div className='card cal2'>
                <h2>Calculator</h2>

                <div class="box">
                    <div id="show"></div>
                    <ul class="grid btn-grid">
                        <li>1</li>
                        <li>2</li>
                        <li>3</li>
                        <li>+</li>
                        <li>4</li>
                        <li>5</li>
                        <li>6</li>
                        <li>-</li>
                        <li>7</li>
                        <li>8</li>
                        <li>9</li>
                        <li>*</li>
                        <li>(</li>
                        <li>0</li>
                        <li>)</li>
                        <li>/</li>
                        <li>.</li>
                        <button class="btn" id='compute' >Compute</button>
                        <button class="btn" id='reset'   onClick={this.toReset}>Reset</button>
                    </ul>

                </div>
            </div>
        )
    }
}


export default Calculator;

I've edited my code to this version:我已经将我的代码编辑为这个版本:

import React from "react";

class Calculator extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            equ: '',
            answer: 0
        }
    }

    componentDidMount() {
        // Bind <li> to event
        var liList = document.getElementsByTagName("li");
        var expStr = "";

        for (let i = 0; i < liList.length; i++) {
            let li = liList[i];
            li.onclick = () => {
                // 获取中缀表达式(nifix expression)
                expStr += this.textContent;

                // 在页面上显示表达式
                show.innerHTML = expStr;

                // console.log(expStr);
            }
        }

        // 当点击 'Compute' 按钮(id='compute')时
        var show = document.getElementById("show")
        var btnCompute = document.getElementById("compute")
        var btnReset = document.getElementById("reset")

        btnCompute.onclick = function () {
            // function toCompute () {
            if (expStr) {
                show.innerHTML = computeSuffix(nifix2Suffix(strSplit(expStr)));
                expStr = "";
            }
        }

        btnReset.onclick = function () {
            // function toReset () {

            show.innerHTML = "请输入计算式";
            expStr = "";
        }

        // 按键触发事件
        document.onkeypress = function (evt) {
            // 获取按键值
            console.log(evt.key)

            if (evt.key === "Enter") {
                // 'Enter'
                show.innerHTML = computeSuffix(nifix2Suffix(strSplit(expStr)))
                expStr = ""
            } else {
                // 其他按键
                expStr += evt.key
                show.innerHTML = expStr
            }

            // console.log(expStr, "expStr")
        }


        // ======================
        // nifix exp: string => array
        // ======================

        // 表达式分割
        function strSplit(expStr) {
            // 操作数左下标
            var index = 0, list = [];

            for (var i = 0; i < expStr.length; i++) {
                // 忽略空格
                if (expStr[i] === " ") {
                    continue;
                }

                // 如果是操作符
                // 1. 先将操作符前的操作数加入到数组中(判断是否为空)
                // 2. 再将操作符本身加入到数组中
                // 3. 将左下标后移一位
                if ("+-*/()".indexOf(expStr[i]) !== -1) {
                    if (expStr.slice(index, i)) {
                        list.push(expStr.slice(index, i));
                    }
                    list.push(expStr[i]);

                    index = i + 1;
                }
            }

            // 循环结束判断是否存在最后一位操作数,存在,加入数组
            if (i === expStr.length && expStr.slice(index, i)) {
                list.push(expStr.slice(index, i));
            }
            return list;
        }

        // =====================
        // 中缀表达式 => 后缀表达式
        // =====================
        function nifix2Suffix(exlist) {

            // 栈的创建
            var opStack = {
                value: [],
                push: function (item) { this.value.push(item) },
                pop: function () { return this.value.pop() },
                peek: function () { return this.value[this.value.length - 1] },
                isEmpty: function () { return this.value.length === 0 },
                size: function () { return this.value.length }
            }

            // 定义优先级判断
            var dicPriority = {};
            dicPriority['*'] = 3;
            dicPriority['/'] = 3;
            dicPriority['+'] = 2;
            dicPriority['-'] = 2;
            dicPriority['('] = 1;

            // 列表存储转换的后缀表达式
            var suffix = [];

            for (var i of exlist) {

                if ("+-*/()".indexOf(i) === -1) {
                    // 操作数直接添加到列表中
                    suffix.push(i)

                } else if (i === "(") {
                    opStack.push(i)
                } else if (i === ")") {
                    while (opStack.peek() !== "(") {
                        suffix.push(opStack.pop())
                    }
                    opStack.pop()
                } else {
                    while (!opStack.isEmpty() && dicPriority[opStack.peek()] >= dicPriority[i]) {
                        suffix.push(opStack.pop())
                    }
                    opStack.push(i)
                }
            }

            while (!opStack.isEmpty() && opStack.peek() !== "") {
                suffix.push(opStack.pop())
            }

            // console.log(suffix, "后缀数组")

            return suffix
        }

        // var prefix = "a+b*c+(d*e+f)*g"

        // console.log(nifix2Suffix(prefix))
        // 检验栈对象是否成功
        // console.log(opStack.value)
        // console.log(opStack.push(5))
        // console.log(opStack.value)
        // console.log(opStack.push(10))
        // console.log(opStack.peek())
        // console.log(opStack.isEmpty())
        // console.log(opStack.size())
        // console.log(opStack.value)



        // ============
        // 后缀表达式计算
        // ============
        function computeSuffix(exlist) {

            // 如果接收的是空数组
            // 代表表达式错误 / 用户未输入
            if (exlist.length === 0) {
                return "请输入正确的表达式"
            }

            // 栈的创建
            var opStack = {
                value: [],
                push: function (item) { this.value.push(item) },
                pop: function () { return this.value.pop() },
                peek: function () { return this.value[this.value.length - 1] },
                isEmpty: function () { return this.value.length === 0 },
                size: function () { return this.value.length }
            }

            for (var i = 0; i < exlist.length; i++) {
                // 遍历表达式
                switch (exlist[i]) {
                    case "+":
                        opStack.push(opStack.pop() + opStack.pop())
                        break
                    case "-":
                        var jianshu = opStack.pop()
                        opStack.push(opStack.pop() - jianshu)
                        break
                    case "*":
                        opStack.push(opStack.pop() * opStack.pop())
                        break
                    case "/":
                        var chushu = opStack.pop()
                        opStack.push(opStack.pop() / chushu)
                        break
                    default:
                        opStack.push(parseFloat(exlist[i]))
                }
            }

            var result = opStack.pop()

            // console.log(result, "后缀结果")

            if (isNaN(result)) {
                return "计算出错啦!"
            }
            return result % 1 === 0 ? result : result.toFixed(2)
        }

    }

    render() {
        return (
            <div className='card cal2'>
                <h2>Calculator</h2>

                <div class="box">
                    <div id="show"></div>
                    <ul class="grid btn-grid">
                        <li>1</li>
                        <li>2</li>
                        <li>3</li>
                        <li>+</li>
                        <li>4</li>
                        <li>5</li>
                        <li>6</li>
                        <li>-</li>
                        <li>7</li>
                        <li>8</li>
                        <li>9</li>
                        <li>*</li>
                        <li>(</li>
                        <li>0</li>
                        <li>)</li>
                        <li>/</li>
                        <li>.</li>
                        <button class="btn" id='compute' >Compute</button>
                        <button class="btn" id='reset'   onClick={this.toReset}>Reset</button>
                    </ul>

                </div>
            </div>
        )
    }
}


export default Calculator;

The previous problem was solved, but here comes a new problem.之前的问题解决了,但是新的问题又来了。 When click on the <li> items, it shows undefined, but I didn't change that part of code.单击<li>项时,它显示未定义,但我没有更改那部分代码。 Why would this happen?为什么会发生这种情况?

The time you are trying to get button references by invoking getElementById, the UI is not rendered yet.当您尝试通过调用 getElementById 获取按钮引用时,UI 尚未呈现。 That is why they are null.这就是为什么它们是 null。 You should get those reference after mounting of the component.您应该在安装组件后获得这些参考。

Use React.createRef使用 React.createRef

In constructor:在构造函数中:

this.computeRef = React.createRef();

In return html:作为回报 html:

<button class="btn" id="compute" ref={this.computeRef}>Compute</button>

While accessing:访问时:

const computeRefNode = this.computeRef.current;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 TypeError:无法读取 null react.js 应用程序的属性“classList” - TypeError: Cannot read property 'classList' of null react.js application React.js TypeError:无法读取 null 的属性“地图” - React.js TypeError: Cannot read property 'map' of null 类型错误:无法读取 null React.js 的属性“地图” - TypeError: Cannot read property 'map' of null React.js TypeError:使用 React.Js 时无法设置 null 的属性“innerHTML” - TypeError: Cannot set property 'innerHTML' of null while using React.Js 我收到错误未捕获的TypeError:无法将属性&#39;onclick&#39;设置为null - I get an error Uncaught TypeError: Cannot set property 'onclick' of null 我收到一个未捕获的类型错误:无法设置 null 的属性“onclick” - i am getting an Uncaught TypeError: Cannot set property 'onclick' of null ReactJS TypeError:无法设置 null 的属性“onclick” - ReactJS TypeError: Cannot set property 'onclick' of null TypeError:无法设置null的属性&#39;onclick&#39; - TypeError: Cannot Set property 'onclick' of null 未捕获的TypeError:无法将属性&#39;onclick&#39;设置为null - Uncaught TypeError: Cannot set property 'onclick' of null React.js 处理 json 中的缺失数据(TypeError: Cannot read property 'prefix' of null) - React.js deal with missing data in json (TypeError: Cannot read property 'prefix' of null)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM