简体   繁体   English

即使导入了我的函数,该函数也无法在另一个函数范围之外工作

[英]My function not working outside of another function scope even though I have imported it

I'm trying to figure out whats going on with my code down below, I have imported my function using import { getTodos } from './todos' into another file called views.js . 我试图找出下面的代码是怎么回事,我已经使用import { getTodos } from './todos'将函数import { getTodos } from './todos'到另一个名为views.js文件中。 I'm trying to call getTodos in the top level of views.js , but I get an error that it's not a function (it's undefined ). 我想打电话给getTodos中的顶级views.js ,但我得到一个错误,它不是一个函数(它是undefined )。 But once I try using getTodos inside a function in the same module, it suddenly works!? 但是,一旦我尝试在同一模块的函数中使用getTodos ,它就会突然起作用! Why is it suddenly no longer undefined, and how can I fix the code so that it's defined where I want it to be? 为什么突然不再定义它了,我该如何修复代码,以便将其定义在我希望的位置?

My todos.js file which includes defining getTodos function: 我的todos.js文件包括定义getTodos函数:

import uuidv4 from 'uuid/v4'
import { renderTodos } from './views'

let todos = []

const loadTodos = () => {
    const todosJSON = localStorage.getItem('todos')
    try {
        return todosJSON ? JSON.parse(todosJSON) : []
    } catch (e) {
        return []
    }
}


todos = loadTodos()

const getTodos = () => todos


const saveTodos = () => {
    localStorage.setItem('todos', JSON.stringify(todos))
}


const createTodo = (text) => {

    if (text.length > 0) {
        todos.push({
            id: uuidv4(),
            text,
            completed: false
        })
        saveTodos()
        renderTodos()
    }

}

const removeTodo = (id) => {
    const todoIndex = todos.findIndex((todo) => todo.id === id)

    if (todoIndex > -1) {
        todos.splice(todoIndex, 1)
        saveTodos()
    }
}

const toggleTodo = (id) => {
    const todo = todos.find((todo) => todo.id === id)

    if (todo) {
        todo.completed = !todo.completed
        saveTodos()
    }
}



export { loadTodos, getTodos, createTodo, removeTodo, toggleTodo }


My views.js file which Im trying to load getTodos in it then use it: 我试图加载getTodos的我的views.js文件然后使用它:

import { getTodos, saveTodos, toggleTodo, removeTodo  } from './todos'
import { getFilters } from './filters'

const todos = getTodos()
const renderTodos = () => {

    const filters = getFilters()
    const todosEl = document.querySelector('#todos')

    const filteredTodos = todos.filter((todo) => {
        const searchTextMatch = todo.text.toLowerCase().includes(filters.searchText.toLowerCase())
        const hideCompletedMatch = !filters.hideCompleted || !todo.completed

        return searchTextMatch && hideCompletedMatch
    })

    const incompleteTodos = filteredTodos.filter((todo) => !todo.completed)

    todosEl.innerHTML = ''
    todosEl.appendChild(generateSummaryDOM(incompleteTodos))

    if (todos.length > 0) {
        filteredTodos.forEach((todo) => {
            todosEl.appendChild(generateTodoDOM(todo))
        })
    } else {
        const emptyMessage = document.createElement('p')
        emptyMessage.textContent = 'No to-dos to show, go ahead and add some!'
        emptyMessage.classList.add('empty-message')
        todosEl.appendChild(emptyMessage)
    }
}


const generateTodoDOM = (todo) => {

    const todoEl = document.createElement('label')
    const containerEl = document.createElement('div')
    const checkbox = document.createElement('input')
    const removeButton = document.createElement('button')
    const span = document.createElement('span')


    // Setup Container
    todoEl.classList.add('list-item')
    containerEl.classList.add('list-item__container')
    todoEl.appendChild(containerEl)

    // Setup Remove Button
    removeButton.textContent = 'remove'
    removeButton.classList.add('button', 'button--text')
    removeButton.addEventListener('click', () => {
        removeTodo(todo.id)
        renderTodos()
    })
    span.textContent = todo.text


    // Setup Checkbox
    checkbox.setAttribute('type', 'checkbox')
    checkbox.checked = todo.completed
    checkbox.addEventListener('change', (e) => {
        toggleTodo(todo.id)
        renderTodos()
    })
    containerEl.appendChild(checkbox)


    containerEl.appendChild(span)
    todoEl.appendChild(removeButton)

    return todoEl
}

const generateSummaryDOM = (incompleteTodos) => {
    const summary = document.createElement('h2')
    summary.classList.add('list-title')
    const plural =  incompleteTodos.length === 1 ? '' : 's'
    summary.textContent = `You have ${incompleteTodos.length} todo${plural} left`
    return summary
}

// Make sure to set up the exports

export { generateSummaryDOM, renderTodos, generateTodoDOM }

index.js file: index.js文件:

import { createTodo } from './todos'
import { renderTodos } from './views'
import { setFilters } from './filters'

// Render initial todos

renderTodos()

// Set up search text handler

document.querySelector('#search-todos').addEventListener('input', (e) => {
    setFilters({
        searchText: e.target.value
    })
    renderTodos()
})

// Set up checkbox handler

document.querySelector('#hide-completed').addEventListener('change', (e) => {
    setFilters({
        hideCompleted: e.target.checked
    })
    renderTodos()
})

// Set up form submission handler

document.querySelector('#add-todo').addEventListener('submit', (e) => {
    e.preventDefault()
    const text = e.target.elements.addTodoText.value.trim()
    createTodo(text)
    e.target.elements.addTodoText.value = ''
})

The errors in the chrome debugger console im getting are: chrome调试器控制台中出现的错误是:

views.js:4 Uncaught TypeError: (0 , _todos.getTodos) is not a function
    at Object../src/views.js (views.js:4)
    at __webpack_require__ (bootstrap:19)
    at Object../src/todos.js (todos.js:2)
    at __webpack_require__ (bootstrap:19)
    at Object../src/index.js (index.js:1)
    at __webpack_require__ (bootstrap:19)
    at Object.0 (bundle.js:20254)
    at __webpack_require__ (bootstrap:19)
    at bootstrap:68
    at bootstrap:68

I'm just trying to understand why this strange behavior is happening, because once I use getTodos inside renderTodos it actually works and I'm not getting any errors, like this: 我只是想了解为什么会发生这种奇怪的行为,因为一旦我在renderTodos使用了getTodos,它实际上就可以工作了,而且我没有收到任何错误,例如:

const renderTodos = () => {
    const todos = getTodos()
    // Other stuffs
}

I'm using Babel and Webpack. 我正在使用Babel和Webpack。

The main problem is that you have a circular dependency. 主要问题是您具有循环依赖关系。 For a more minimal example which can illustrate the problem, consider: 对于可以说明问题的更简单的示例,请考虑:

// foo.js
import bar from './bar';
const x = bar();
export default () => x;

// bar.js
import foo from './foo';
const y = foo();
export default () => y;

In the above code, just like in your code, you have modules which are using an import, where said import also depends on importing something from the current module. 在上面的代码中,就像您的代码一样,您有使用导入的模块,其中所述导入取决于从当前模块中导入什么。 If A imports from B, and B also imports from A, then you need to make sure that neither A nor B use anything from each other before both of their top-level code has finished completely - otherwise, you can't depend on the other import being defined at that time. 如果A从B导入,并且B也从A导入,那么您需要确保A和B在它们的两个顶级代码完全完成之前都不会使用彼此的任何东西-否则,您不能依赖于当时正在定义其他导入。

It would be best to refactor the code to remove the circular dependency somehow. 最好重构代码以某种方式消除循环依赖。

A pattern I like to use is to make sure top-level code in a module does not initiate anything - rather, it's nice when everything can ultimately kicked off from the entry point (which, here, looks to be index.js ). 我喜欢使用的一种模式是确保模块中的顶级代码不会启动任何东西-而是,当一切最终都可以从入口点开始时 (在这里看起来是index.js ),这很好。 A quick fix would be for each module to export a function which runs the initialization code, rather than putting that code on the top level. 一个快速的解决方案是为每个模块导出运行初始化代码的功能 ,而不是将该代码放在顶层。 For example: 例如:

// views.js

import { getTodos, saveTodos, toggleTodo, removeTodo  } from './todos'
import { getFilters } from './filters'

let todos;
const init = () => {
  todos = getTodos();
};
// ... everything else
export { generateSummaryDOM, renderTodos, generateTodoDOM, init }

Then have index.js import and call init at the very beginning, right after importing everything. 然后,在导入所有内容之后,立即开始index.js import并调用init

Luckily, since todos.js only calls (the cross-module, imported) renderTodos in its createTodo function, and createTodo is exported but not called in todos.js , it doesn't need to be changed. 幸运的是,因为todos.js仅调用(跨模块,进口) renderTodos在其createTodo功能, createTodo出口,但不叫todos.js ,它并不需要改变。

Another (probably better) option would be to remove todos.js 's dependancy on renderTodos . 另一个(可能更好)选择是去除todos.js上的扶养renderTodos In todos.js , you're currently only using renderTodos in its createTodo function. todos.js ,您目前只使用renderTodos在其createTodo功能。 Consider changing thigns so that createTodo creates and saves the todo, but does not render it with renderTodos - instead, look for where createTodo is used (which looks to be only in index.js ), and have index.js call renderTodos instead: 考虑更改thign,以便createTodo创建和保存待办事项,但不使用renderTodos渲染它-而是查找使用createTodo位置(看起来仅在index.js ),并使用index.js代替renderTodos

// todos.js

// do not import renderTodos here

// ...
const createTodo = (text) => {
    if (text.length > 0) {
        todos.push({
            id: uuidv4(),
            text,
            completed: false
        })
        saveTodos()
    }
}

and

// index.js

// ...
document.querySelector('#add-todo').addEventListener('submit', (e) => {
    e.preventDefault()
    const text = e.target.elements.addTodoText.value.trim()
    createTodo(text)
    renderTodos();
    e.target.elements.addTodoText.value = ''
})

暂无
暂无

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

相关问题 即使我有一个数组,map 也不是 function - map is not a function even though I have an array jQuery函数即使已导入也无法定义 - jquery function can not be defined even though it is imported 为什么该变量在 function 内部工作,但当它放在 function 外部时却没有工作,尽管它具有全局 scope? - why the variable is working inside the function but not when it is placed outside the function though it has global scope? array.map 不是 function 即使我输入正确 - array.map is not a function even though I have it typed correctly 找不到 P5 DOM 函数“选择”,即使我已经导入了 p5.dom.js - P5 DOM function 'select' is not being found, even though I've imported p5.dom.js 如何在 addEventListener function scope 之外减去我的 var - how can i substract my var outside of addEventListener function scope 即使我的代码看起来很好,我仍然会收到“未捕获的TypeError:字符串不是函数”错误。任何人都可以看看并解释一下吗? - I keep getting a “Uncaught TypeError: string is not a function” error, even though my code seems to be fine. Can anyone have a look and explain? 如何在我的 function 的 scope 之外设置变量? - How to set a variable outside the scope of my function? setState 即使在渲染函数之外也会导致无限循环 - setState causes infinite loop even though it is outside render function 我收到错误 $(...).modal is not a function 即使在 jQuery 之后导入 bootstrap 我该如何解决这个问题(使用 npm 版本)? - I get the error $(...).modal is not a function even though bootstrap is imported after jQuery how can i fix this (using npm versions)?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM