Your original code generally works -- the quoting is a bit off (and how much that matters is version-specific: you wouldn't see your original bug on a newer version of bash), but nothing further.
After:
# assign string
string='this is several words'
# split string to a list
IFS=' ' read -r -a list <<<"$string"
...you can run:
# print a definition of the variable list
$ declare -p list
declare -a list=([0]="this" [1]="is" [2]="several" [3]="words")
# print each item in the list array on a separate line
$ printf ' - %s\n' "${list[@]}"
- this
- is
- several
- words
# still works with echo; change IFS to show that we're really an array
$ IFS=':' echo "${list[*]}"
this:is:several:words
More importantly, it also works in cases where the competing answer doesn't:
# need to be in a non-empty directory to demonstrate
$ touch a.txt b.txt c.txt
# put literal asterisks as separate words in our string
$ string='list * contains * asterisks'
# reading those using read -a works fine
$ IFS=' ' read -r -a list <<<"$string"
# whereas the array=( $string ) is NOT fine
$ IFS=' '; buggyList=( $string )
# print both arrays' contents
$ declare -p list buggyList
declare -a list=([0]="list" [1]="*" [2]="contains" [3]="*" [4]="asterisks")
declare -a buggyList=([0]="list" [1]="a.txt" [2]="b.txt" [3]="c.txt" [4]="contains" [5]="a.txt" [6]="b.txt" [7]="c.txt" [8]="asterisks")
As you can see, the list=( $string ) answer gets filenames injected into its contents, but the read -a list contains exactly the word-split contents of your original string.